diff options
author | Sam Roberts <vieuxtech@gmail.com> | 2018-11-09 15:05:34 -0800 |
---|---|---|
committer | Sam Roberts <vieuxtech@gmail.com> | 2018-11-20 13:21:08 -0800 |
commit | fe303b9b2dd8224e368ed69d6b797bc34dd94d07 (patch) | |
tree | 2591608d18e88eb9c21a099c0ef02eff0f8291d3 /src | |
parent | a856406c2dc0f6edf9b33067cd91fa1a71eab041 (diff) | |
download | android-node-v8-fe303b9b2dd8224e368ed69d6b797bc34dd94d07.tar.gz android-node-v8-fe303b9b2dd8224e368ed69d6b797bc34dd94d07.tar.bz2 android-node-v8-fe303b9b2dd8224e368ed69d6b797bc34dd94d07.zip |
tls: include elliptic curve X.509 public key info
X.509 certs are provided to the user in a parsed object form by a number
of TLS APIs. Include public key info for elliptic curves as well, not
just RSA.
- pubkey: the public key
- bits: the strength of the curve
- asn1Curve: the ASN.1 OID for the curve
- nistCurve: the NIST nickname for the curve, if it has one
PR-URL: https://github.com/nodejs/node/pull/24358
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Diffstat (limited to 'src')
-rw-r--r-- | src/env.h | 3 | ||||
-rw-r--r-- | src/node_crypto.cc | 65 | ||||
-rw-r--r-- | src/node_crypto.h | 1 |
3 files changed, 67 insertions, 2 deletions
@@ -124,7 +124,9 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; V(address_string, "address") \ V(aliases_string, "aliases") \ V(args_string, "args") \ + V(asn1curve_string, "asn1Curve") \ V(async_ids_stack_string, "async_ids_stack") \ + V(bits_string, "bits") \ V(buffer_string, "buffer") \ V(bytes_parsed_string, "bytesParsed") \ V(bytes_read_string, "bytesRead") \ @@ -207,6 +209,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; V(modulus_string, "modulus") \ V(name_string, "name") \ V(netmask_string, "netmask") \ + V(nistcurve_string, "nistCurve") \ V(nsname_string, "nsname") \ V(ocsp_request_string, "OCSPRequest") \ V(onaltsvc_string, "onaltsvc") \ diff --git a/src/node_crypto.cc b/src/node_crypto.cc index cf50821314..91583c18d9 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -52,6 +52,15 @@ static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL | XN_FLAG_FN_SN; namespace node { +namespace Buffer { +// OpenSSL uses `unsigned char*` for raw data, make this easier for us. +v8::MaybeLocal<v8::Object> New(Environment* env, unsigned char* udata, + size_t length) { + char* data = reinterpret_cast<char*>(udata); + return Buffer::New(env, data, length); +} +} // namespace Buffer + namespace crypto { using v8::Array; @@ -1652,8 +1661,17 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) { EVPKeyPointer pkey(X509_get_pubkey(cert)); RSAPointer rsa; - if (pkey) - rsa.reset(EVP_PKEY_get1_RSA(pkey.get())); + ECPointer ec; + if (pkey) { + switch (EVP_PKEY_id(pkey.get())) { + case EVP_PKEY_RSA: + rsa.reset(EVP_PKEY_get1_RSA(pkey.get())); + break; + case EVP_PKEY_EC: + ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get())); + break; + } + } if (rsa) { const BIGNUM* n; @@ -1689,10 +1707,53 @@ static Local<Object> X509ToObject(Environment* env, X509* cert) { reinterpret_cast<unsigned char*>(Buffer::Data(pubbuff)); i2d_RSA_PUBKEY(rsa.get(), &pubserialized); info->Set(env->context(), env->pubkey_string(), pubbuff).FromJust(); + } else if (ec) { + const EC_GROUP* group = EC_KEY_get0_group(ec.get()); + if (group != nullptr) { + int bits = EC_GROUP_order_bits(group); + if (bits > 0) { + info->Set(context, env->bits_string(), + Integer::New(env->isolate(), bits)).FromJust(); + } + } + + unsigned char* pub = nullptr; + size_t publen = EC_KEY_key2buf(ec.get(), EC_KEY_get_conv_form(ec.get()), + &pub, nullptr); + if (publen > 0) { + Local<Object> buf = Buffer::New(env, pub, publen).ToLocalChecked(); + // Ownership of pub pointer accepted by Buffer. + pub = nullptr; + info->Set(context, env->pubkey_string(), buf).FromJust(); + } else { + CHECK_NULL(pub); + } + + if (EC_GROUP_get_asn1_flag(group) != 0) { + // Curve is well-known, get its OID and NIST nick-name (if it has one). + + int nid = EC_GROUP_get_curve_name(group); + if (nid != 0) { + if (const char* sn = OBJ_nid2sn(nid)) { + info->Set(context, env->asn1curve_string(), + OneByteString(env->isolate(), sn)).FromJust(); + } + } + if (nid != 0) { + if (const char* nist = EC_curve_nid2nist(nid)) { + info->Set(context, env->nistcurve_string(), + OneByteString(env->isolate(), nist)).FromJust(); + } + } + } else { + // Unnamed curves can be described by their mathematical properties, + // but aren't used much (at all?) with X.509/TLS. Support later if needed. + } } pkey.reset(); rsa.reset(); + ec.reset(); ASN1_TIME_print(bio.get(), X509_get_notBefore(cert)); BIO_get_mem_ptr(bio.get(), &mem); diff --git a/src/node_crypto.h b/src/node_crypto.h index f85cdd3208..5f98af754e 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -81,6 +81,7 @@ using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>; using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>; using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>; using RSAPointer = DeleteFnPtr<RSA, RSA_free>; +using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>; using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>; using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>; using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>; |