This source file includes following definitions.
- RsaMethodPubEnc
- RsaMethodPubDec
- RsaMethodPrivEnc
- RsaMethodPrivDec
- RsaMethodInit
- RsaMethodFinish
- CopyBigNumFromBytes
- SwapBigNumPtrFromBytes
- GetRsaPkeyWrapper
- GetRsaLegacyKey
- DsaMethodDoSign
- DsaMethodSignSetup
- DsaMethodDoVerify
- DsaMethodFinish
- GetDsaPkeyWrapper
- ExDataFree
- ExDataDup
- ex_data_index
- EcdsaGetExDataIndex
- EcdsaMethodDoSign
- EcdsaMethodSignSetup
- EcdsaMethodDoVerify
- GetEcdsaPkeyWrapper
- GetOpenSSLPrivateKeyWrapper
#include "net/android/keystore_openssl.h"
#include <jni.h>
#include <openssl/bn.h>
#include <openssl/crypto/ecdsa/ecs_locl.h>
#include <openssl/crypto/ec/ec_lcl.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include "base/android/build_info.h"
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/basictypes.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "crypto/openssl_util.h"
#include "net/android/keystore.h"
#include "net/ssl/ssl_client_cert_type.h"
using base::android::ScopedJavaGlobalRef;
namespace net {
namespace android {
namespace {
typedef crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> ScopedEVP_PKEY;
typedef crypto::ScopedOpenSSL<RSA, RSA_free> ScopedRSA;
typedef crypto::ScopedOpenSSL<DSA, DSA_free> ScopedDSA;
typedef crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ScopedEC_KEY;
typedef crypto::ScopedOpenSSL<EC_GROUP, EC_GROUP_free> ScopedEC_GROUP;
int RsaMethodPubEnc(int flen,
const unsigned char* from,
unsigned char* to,
RSA* rsa,
int padding) {
NOTIMPLEMENTED();
RSAerr(RSA_F_RSA_PUBLIC_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
return -1;
}
int RsaMethodPubDec(int flen,
const unsigned char* from,
unsigned char* to,
RSA* rsa,
int padding) {
NOTIMPLEMENTED();
RSAerr(RSA_F_RSA_PUBLIC_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
return -1;
}
int RsaMethodPrivEnc(int flen,
const unsigned char *from,
unsigned char *to,
RSA *rsa,
int padding) {
DCHECK_EQ(RSA_PKCS1_PADDING, padding);
if (padding != RSA_PKCS1_PADDING) {
RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
return -1;
}
jobject private_key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
if (!private_key) {
LOG(WARNING) << "Null JNI reference passed to RsaMethodPrivEnc!";
RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
return -1;
}
base::StringPiece from_piece(reinterpret_cast<const char*>(from), flen);
std::vector<uint8> result;
if (!RawSignDigestWithPrivateKey(private_key, from_piece, &result)) {
LOG(WARNING) << "Could not sign message in RsaMethodPrivEnc!";
RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
return -1;
}
size_t expected_size = static_cast<size_t>(RSA_size(rsa));
if (result.size() > expected_size) {
LOG(ERROR) << "RSA Signature size mismatch, actual: "
<< result.size() << ", expected <= " << expected_size;
RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR);
return -1;
}
size_t zero_pad = expected_size - result.size();
memset(to, 0, zero_pad);
memcpy(to + zero_pad, &result[0], result.size());
return expected_size;
}
int RsaMethodPrivDec(int flen,
const unsigned char* from,
unsigned char* to,
RSA* rsa,
int padding) {
NOTIMPLEMENTED();
RSAerr(RSA_F_RSA_PRIVATE_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED);
return -1;
}
int RsaMethodInit(RSA* rsa) {
return 0;
}
int RsaMethodFinish(RSA* rsa) {
jobject key = reinterpret_cast<jobject>(RSA_get_app_data(rsa));
if (key != NULL) {
RSA_set_app_data(rsa, NULL);
ReleaseKey(key);
}
return 0;
}
const RSA_METHOD android_rsa_method = {
"Android signing-only RSA method",
RsaMethodPubEnc,
RsaMethodPubDec,
RsaMethodPrivEnc,
RsaMethodPrivDec,
NULL,
NULL,
RsaMethodInit,
RsaMethodFinish,
RSA_METHOD_FLAG_NO_CHECK,
NULL,
NULL,
NULL,
NULL,
};
bool CopyBigNumFromBytes(const std::vector<uint8>& new_bytes,
BIGNUM* num) {
BIGNUM* ret = BN_bin2bn(
reinterpret_cast<const unsigned char*>(&new_bytes[0]),
static_cast<int>(new_bytes.size()),
num);
return (ret != NULL);
}
bool SwapBigNumPtrFromBytes(const std::vector<uint8>& new_bytes,
BIGNUM** num_ptr) {
BIGNUM* old_num = *num_ptr;
BIGNUM* new_num = BN_bin2bn(
reinterpret_cast<const unsigned char*>(&new_bytes[0]),
static_cast<int>(new_bytes.size()),
old_num);
if (new_num == NULL)
return false;
if (old_num == NULL)
*num_ptr = new_num;
return true;
}
bool GetRsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) {
ScopedRSA rsa(RSA_new());
RSA_set_method(rsa.get(), &android_rsa_method);
std::vector<uint8> modulus;
if (!GetRSAKeyModulus(private_key, &modulus)) {
LOG(ERROR) << "Failed to get private key modulus";
return false;
}
if (!SwapBigNumPtrFromBytes(modulus, &rsa.get()->n)) {
LOG(ERROR) << "Failed to decode private key modulus";
return false;
}
ScopedJavaGlobalRef<jobject> global_key;
global_key.Reset(NULL, private_key);
if (global_key.is_null()) {
LOG(ERROR) << "Could not create global JNI reference";
return false;
}
RSA_set_app_data(rsa.get(), global_key.Release());
EVP_PKEY_assign_RSA(pkey, rsa.release());
return true;
}
EVP_PKEY* GetRsaLegacyKey(jobject private_key) {
EVP_PKEY* sys_pkey =
GetOpenSSLSystemHandleForPrivateKey(private_key);
if (sys_pkey != NULL) {
CRYPTO_add(&sys_pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
} else {
std::vector<uint8> encoded;
if (!GetPrivateKeyEncodedBytes(private_key, &encoded)) {
LOG(ERROR) << "Can't get private key data!";
return NULL;
}
const unsigned char* p =
reinterpret_cast<const unsigned char*>(&encoded[0]);
int len = static_cast<int>(encoded.size());
sys_pkey = d2i_AutoPrivateKey(NULL, &p, len);
if (sys_pkey == NULL) {
LOG(ERROR) << "Can't convert private key data!";
return NULL;
}
}
return sys_pkey;
}
DSA_SIG* DsaMethodDoSign(const unsigned char* dgst,
int dlen,
DSA* dsa) {
jobject private_key = reinterpret_cast<jobject>(DSA_get_ex_data(dsa, 0));
if (private_key == NULL)
return NULL;
std::vector<uint8> signature;
if (!RawSignDigestWithPrivateKey(
private_key,
base::StringPiece(
reinterpret_cast<const char*>(dgst),
static_cast<size_t>(dlen)),
&signature)) {
return NULL;
}
size_t max_expected_size = static_cast<size_t>(DSA_size(dsa));
if (signature.size() > max_expected_size) {
LOG(ERROR) << "DSA Signature size mismatch, actual: "
<< signature.size() << ", expected <= "
<< max_expected_size;
return NULL;
}
const unsigned char* sigbuf =
reinterpret_cast<const unsigned char*>(&signature[0]);
int siglen = static_cast<size_t>(signature.size());
DSA_SIG* dsa_sig = d2i_DSA_SIG(NULL, &sigbuf, siglen);
return dsa_sig;
}
int DsaMethodSignSetup(DSA* dsa,
BN_CTX* ctx_in,
BIGNUM** kinvp,
BIGNUM** rp) {
NOTIMPLEMENTED();
DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_INVALID_DIGEST_TYPE);
return -1;
}
int DsaMethodDoVerify(const unsigned char* dgst,
int dgst_len,
DSA_SIG* sig,
DSA* dsa) {
NOTIMPLEMENTED();
DSAerr(DSA_F_DSA_DO_VERIFY, DSA_R_INVALID_DIGEST_TYPE);
return -1;
}
int DsaMethodFinish(DSA* dsa) {
jobject key = reinterpret_cast<jobject>(DSA_get_ex_data(dsa,0));
if (key != NULL) {
DSA_set_ex_data(dsa, 0, NULL);
ReleaseKey(key);
}
return 0;
}
const DSA_METHOD android_dsa_method = {
"Android signing-only DSA method",
DsaMethodDoSign,
DsaMethodSignSetup,
DsaMethodDoVerify,
NULL,
NULL,
NULL,
DsaMethodFinish,
0,
NULL,
NULL,
NULL
};
bool GetDsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) {
ScopedDSA dsa(DSA_new());
DSA_set_method(dsa.get(), &android_dsa_method);
std::vector<uint8> q;
if (!GetDSAKeyParamQ(private_key, &q)) {
LOG(ERROR) << "Can't extract Q parameter from DSA private key";
return false;
}
if (!SwapBigNumPtrFromBytes(q, &dsa.get()->q)) {
LOG(ERROR) << "Can't decode Q parameter from DSA private key";
return false;
}
ScopedJavaGlobalRef<jobject> global_key;
global_key.Reset(NULL, private_key);
if (global_key.is_null()) {
LOG(ERROR) << "Could not create global JNI reference";
return false;
}
DSA_set_ex_data(dsa.get(), 0, global_key.Release());
EVP_PKEY_assign_DSA(pkey, dsa.release());
return true;
}
void ExDataFree(void* parent,
void* ptr,
CRYPTO_EX_DATA* ad,
int idx,
long argl,
void* argp) {
jobject private_key = reinterpret_cast<jobject>(ptr);
if (private_key == NULL)
return;
CRYPTO_set_ex_data(ad, idx, NULL);
ReleaseKey(private_key);
}
int ExDataDup(CRYPTO_EX_DATA* to,
CRYPTO_EX_DATA* from,
void* from_d,
int idx,
long argl,
void* argp) {
CHECK(false) << "ExDataDup was called for ECDSA custom key !?";
return 0;
}
class EcdsaExDataIndex {
public:
int ex_data_index() { return ex_data_index_; }
EcdsaExDataIndex() {
ex_data_index_ = ECDSA_get_ex_new_index(0,
NULL,
NULL,
ExDataDup,
ExDataFree);
}
private:
int ex_data_index_;
};
int EcdsaGetExDataIndex(void) {
static base::LazyInstance<EcdsaExDataIndex>::Leaky s_instance =
LAZY_INSTANCE_INITIALIZER;
return s_instance.Get().ex_data_index();
}
ECDSA_SIG* EcdsaMethodDoSign(const unsigned char* dgst,
int dgst_len,
const BIGNUM* inv,
const BIGNUM* rp,
EC_KEY* eckey) {
jobject private_key = reinterpret_cast<jobject>(
ECDSA_get_ex_data(eckey, EcdsaGetExDataIndex()));
if (!private_key) {
LOG(WARNING) << "Null JNI reference passed to EcdsaMethodDoSign!";
return NULL;
}
std::vector<uint8> signature;
base::StringPiece digest(
reinterpret_cast<const char*>(dgst),
static_cast<size_t>(dgst_len));
if (!RawSignDigestWithPrivateKey(
private_key, digest, &signature)) {
LOG(WARNING) << "Could not sign message in EcdsaMethodDoSign!";
return NULL;
}
size_t max_expected_size = static_cast<size_t>(ECDSA_size(eckey));
if (signature.size() > max_expected_size) {
LOG(ERROR) << "ECDSA Signature size mismatch, actual: "
<< signature.size() << ", expected <= "
<< max_expected_size;
return NULL;
}
const unsigned char* sigbuf =
reinterpret_cast<const unsigned char*>(&signature[0]);
long siglen = static_cast<long>(signature.size());
return d2i_ECDSA_SIG(NULL, &sigbuf, siglen);
}
int EcdsaMethodSignSetup(EC_KEY* eckey,
BN_CTX* ctx,
BIGNUM** kinv,
BIGNUM** r) {
NOTIMPLEMENTED();
ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_ERR_EC_LIB);
return -1;
}
int EcdsaMethodDoVerify(const unsigned char* dgst,
int dgst_len,
const ECDSA_SIG* sig,
EC_KEY* eckey) {
NOTIMPLEMENTED();
ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_ERR_EC_LIB);
return -1;
}
const ECDSA_METHOD android_ecdsa_method = {
"Android signing-only ECDSA method",
EcdsaMethodDoSign,
EcdsaMethodSignSetup,
EcdsaMethodDoVerify,
0,
NULL,
};
bool GetEcdsaPkeyWrapper(jobject private_key, EVP_PKEY* pkey) {
ScopedEC_KEY eckey(EC_KEY_new());
ECDSA_set_method(eckey.get(), &android_ecdsa_method);
std::vector<uint8> order;
if (!GetECKeyOrder(private_key, &order)) {
LOG(ERROR) << "Can't extract order parameter from EC private key";
return false;
}
ScopedEC_GROUP group(EC_GROUP_new(EC_GFp_nist_method()));
if (!group.get()) {
LOG(ERROR) << "Can't create new EC_GROUP";
return false;
}
if (!CopyBigNumFromBytes(order, &group.get()->order)) {
LOG(ERROR) << "Can't decode order from PrivateKey";
return false;
}
EC_KEY_set_group(eckey.get(), group.release());
ScopedJavaGlobalRef<jobject> global_key;
global_key.Reset(NULL, private_key);
if (global_key.is_null()) {
LOG(ERROR) << "Can't create global JNI reference";
return false;
}
ECDSA_set_ex_data(eckey.get(),
EcdsaGetExDataIndex(),
global_key.Release());
EVP_PKEY_assign_EC_KEY(pkey, eckey.release());
return true;
}
}
EVP_PKEY* GetOpenSSLPrivateKeyWrapper(jobject private_key) {
ScopedEVP_PKEY pkey(EVP_PKEY_new());
if (!pkey.get())
return NULL;
PrivateKeyType key_type = GetPrivateKeyType(private_key);
switch (key_type) {
case PRIVATE_KEY_TYPE_RSA:
{
const int kAndroid42ApiLevel = 17;
if (base::android::BuildInfo::GetInstance()->sdk_int() <
kAndroid42ApiLevel) {
EVP_PKEY* legacy_key = GetRsaLegacyKey(private_key);
if (legacy_key == NULL)
return NULL;
pkey.reset(legacy_key);
} else {
if (!GetRsaPkeyWrapper(private_key, pkey.get()))
return NULL;
}
}
break;
case PRIVATE_KEY_TYPE_DSA:
if (!GetDsaPkeyWrapper(private_key, pkey.get()))
return NULL;
break;
case PRIVATE_KEY_TYPE_ECDSA:
if (!GetEcdsaPkeyWrapper(private_key, pkey.get()))
return NULL;
break;
default:
LOG(WARNING)
<< "GetOpenSSLPrivateKeyWrapper() called with invalid key type";
return NULL;
}
return pkey.release();
}
}
}