Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(590)

Unified Diff: runtime/bin/secure_socket.cc

Issue 1687533002: Adds support for PKCS12 containers to SecurityContext (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « CHANGELOG.md ('k') | sdk/lib/io/security_context.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/secure_socket.cc
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index fa1f7f117c8a76d849f6aaad438faf90806d8b99..2e0bb880c6742535f6b3afab345966bcc09de1e0 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -12,6 +12,7 @@
#include <openssl/bio.h>
#include <openssl/err.h>
+#include <openssl/pkcs12.h>
#include <openssl/safestack.h>
#include <openssl/ssl.h>
#include <openssl/tls1.h>
@@ -381,11 +382,11 @@ void CheckStatus(int status,
// BIO is allocated. Leaving the scope cleans up the BIO and the buffer that
// was used to create it.
//
-// Do not make Dart_ API calls while in a MemBIOScope.
-// Do not call Dart_PropagateError while in a MemBIOScope.
-class MemBIOScope {
+// Do not make Dart_ API calls while in a ScopedMemBIO.
+// Do not call Dart_PropagateError while in a ScopedMemBIO.
+class ScopedMemBIO {
public:
- explicit MemBIOScope(Dart_Handle object) {
+ explicit ScopedMemBIO(Dart_Handle object) {
if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
Dart_ThrowException(DartUtils::NewDartArgumentError(
"Argument is not a List<int>"));
@@ -418,7 +419,7 @@ class MemBIOScope {
is_typed_data_ = is_typed_data;
}
- ~MemBIOScope() {
+ ~ScopedMemBIO() {
ASSERT(bio_ != NULL);
if (is_typed_data_) {
BIO_free(bio_);
@@ -441,10 +442,113 @@ class MemBIOScope {
bool is_typed_data_;
DISALLOW_ALLOCATION();
- DISALLOW_COPY_AND_ASSIGN(MemBIOScope);
+ DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO);
};
+template<typename T, void (*free_func)(T*)>
+class ScopedSSLType {
+ public:
+ explicit ScopedSSLType(T* obj) : obj_(obj) {}
+
+ ~ScopedSSLType() {
+ if (obj_ != NULL) {
+ free_func(obj_);
+ }
+ }
+
+ T* get() { return obj_; }
+ const T* get() const { return obj_; }
+
+ T* release() {
+ T* result = obj_;
+ obj_ = NULL;
+ return result;
+ }
+
+ private:
+ T* obj_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(ScopedSSLType);
+};
+
+template<typename T, typename E, void (*func)(E*)>
+class ScopedSSLStackType {
+ public:
+ explicit ScopedSSLStackType(T* obj) : obj_(obj) {}
+
+ ~ScopedSSLStackType() {
+ if (obj_ != NULL) {
+ sk_pop_free(reinterpret_cast<_STACK*>(obj_),
+ reinterpret_cast<void (*)(void *)>(func));
+ }
+ }
+
+ T* get() { return obj_; }
+ const T* get() const { return obj_; }
+
+ T* release() {
+ T* result = obj_;
+ obj_ = NULL;
+ return result;
+ }
+
+ private:
+ T* obj_;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType);
+};
+
+typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12;
+typedef ScopedSSLType<X509, X509_free> ScopedX509;
+
+typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack;
+typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free>
+ ScopedX509NAMEStack;
+
+static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
+ ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+ if (p12.get() == NULL) {
+ return NULL;
+ }
+
+ EVP_PKEY* key = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca_certs = NULL;
+ int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
+ if (status == 0) {
+ return NULL;
+ }
+
+ // We only care about the private key.
+ ScopedX509 delete_cert(cert);
+ ScopedX509Stack delete_ca_certs(ca_certs);
+ return key;
+}
+
+
+static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
+ EVP_PKEY *key = PEM_read_bio_PrivateKey(
+ bio, NULL, PasswordCallback, const_cast<char*>(password));
+
+ // If the data doesn't contain the PEM start line, try reading as PKCS12.
+ uint32_t err = ERR_peek_last_error();
+ if ((key == NULL) &&
+ (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+ // Reset the bio, and clear the error from trying to read as PEM.
+ ERR_clear_error();
+ BIO_reset(bio);
+
+ // Try to decode as PKCS12
+ key = GetPrivateKeyPKCS12(bio, password);
+ }
+ return key;
+}
+
+
void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
Dart_NativeArguments args) {
SSL_CTX* context = GetSecurityContext(args);
@@ -467,9 +571,8 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
int status;
{
- MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
- EVP_PKEY *key = PEM_read_bio_PrivateKey(
- bio.bio(), NULL, PasswordCallback, const_cast<char*>(password));
+ ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ EVP_PKEY *key = GetPrivateKey(bio.bio(), password);
status = SSL_CTX_use_PrivateKey(context, key);
}
@@ -480,7 +583,52 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
}
-static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
+static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, BIO* bio) {
+ ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+ if (p12.get() == NULL) {
+ return NULL;
+ }
+
+ EVP_PKEY* key = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca_certs = NULL;
+ // There should be no private keys in this file, so we hardcode the password
+ // to "".
+ // TODO(zra): Allow passing a password anyway.
+ int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
+ if (status == 0) {
+ return status;
+ }
+
+ ScopedX509Stack cert_stack(ca_certs);
+
+ // There should be no private key.
+ if (key != NULL) {
+ X509_free(cert);
+ return 0;
+ }
+
+ X509_STORE* store = SSL_CTX_get_cert_store(context);
+ status = X509_STORE_add_cert(store, cert);
+ if (status == 0) {
+ X509_free(cert);
+ return status;
+ }
+
+ X509* ca;
+ while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
+ status = X509_STORE_add_cert(store, ca);
+ if (status == 0) {
+ X509_free(ca);
+ return status;
+ }
+ }
+
+ return status;
+}
+
+
+static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) {
X509_STORE* store = SSL_CTX_get_cert_store(context);
int status = 0;
@@ -494,11 +642,8 @@ static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
}
uint32_t err = ERR_peek_last_error();
- if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
- (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
- // Reached the end of the buffer.
- ERR_clear_error();
- } else {
+ if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
+ (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
// Some real error happened.
status = 0;
}
@@ -507,12 +652,29 @@ static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
}
+static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
+ int status = SetTrustedCertificatesBytesPEM(context, bio);
+ uint32_t err = ERR_peek_last_error();
+ if ((status == 0) &&
+ (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+ ERR_clear_error();
+ BIO_reset(bio);
+ status = SetTrustedCertificatesBytesPKCS12(context, bio);
+ } else if (status != 0) {
+ // The PEM file was successfully parsed.
+ ERR_clear_error();
+ }
+ return status;
+}
+
+
void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
Dart_NativeArguments args) {
SSL_CTX* context = GetSecurityContext(args);
int status;
{
- MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
status = SetTrustedCertificatesBytes(context, bio.bio());
}
CheckStatus(status,
@@ -539,34 +701,78 @@ void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
}
-static int UseChainBytes(SSL_CTX* context, BIO* bio) {
- int status = 0;
- X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
- if (x509 == NULL) {
+static int UseChainBytesPKCS12(SSL_CTX* context, BIO* bio) {
+ ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+ if (p12.get() == NULL) {
+ return NULL;
+ }
+
+ EVP_PKEY* key = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca_certs = NULL;
+ // There should be no private keys in this file, so we hardcode the password
+ // to "".
+ // TODO(zra): Allow passing a password anyway.
+ int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
+ if (status == 0) {
+ return status;
+ }
+
+ ScopedX509 x509(cert);
+ ScopedX509Stack certs(ca_certs);
+
+ // There should be no private key.
+ if (key != NULL) {
return 0;
}
- status = SSL_CTX_use_certificate(context, x509);
+ status = SSL_CTX_use_certificate(context, x509.get());
if (ERR_peek_error() != 0) {
// Key/certificate mismatch doesn't imply status is 0.
status = 0;
}
if (status == 0) {
- X509_free(x509);
return status;
}
SSL_CTX_clear_chain_certs(context);
- while (true) {
- X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- if (ca == NULL) {
- break;
+ X509* ca;
+ while ((ca = sk_X509_shift(certs.get())) != NULL) {
+ status = SSL_CTX_add0_chain_cert(context, ca);
+ if (status == 0) {
+ X509_free(ca);
+ return status;
}
+ }
+
+ return status;
+}
+
+
+static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
+ int status = 0;
+ ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
+ if (x509.get() == NULL) {
+ return 0;
+ }
+
+ status = SSL_CTX_use_certificate(context, x509.get());
+ if (ERR_peek_error() != 0) {
+ // Key/certificate mismatch doesn't imply status is 0.
+ status = 0;
+ }
+ if (status == 0) {
+ return status;
+ }
+
+ SSL_CTX_clear_chain_certs(context);
+
+ X509* ca;
+ while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
status = SSL_CTX_add0_chain_cert(context, ca);
if (status == 0) {
X509_free(ca);
- X509_free(x509);
return status;
}
// Note that we must not free `ca` if it was successfully added to the
@@ -575,16 +781,29 @@ static int UseChainBytes(SSL_CTX* context, BIO* bio) {
}
uint32_t err = ERR_peek_last_error();
- if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
- (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
- // Reached the end of the buffer.
- ERR_clear_error();
- } else {
+ if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
+ (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
// Some real error happened.
status = 0;
}
- X509_free(x509);
+ return status;
+}
+
+
+static int UseChainBytes(SSL_CTX* context, BIO* bio) {
+ int status = UseChainBytesPEM(context, bio);
+ uint32_t err = ERR_peek_last_error();
+ if ((status == 0) &&
+ (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+ ERR_clear_error();
+ BIO_reset(bio);
+ status = UseChainBytesPKCS12(context, bio);
+ } else if (status != 0) {
+ // The PEM file was successfully parsed.
+ ERR_clear_error();
+ }
return status;
}
@@ -594,7 +813,7 @@ void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
SSL_CTX* context = GetSecurityContext(args);
int status;
{
- MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
status = UseChainBytes(context, bio.bio());
}
CheckStatus(status,
@@ -603,36 +822,120 @@ void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
}
-static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
- STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null();
- if (result == NULL) {
+static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio) {
+ ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+ if (p12.get() == NULL) {
+ return NULL;
+ }
+
+ ScopedX509NAMEStack result(sk_X509_NAME_new_null());
+ if (result.get() == NULL) {
+ return NULL;
+ }
+
+ EVP_PKEY* key = NULL;
+ X509 *cert = NULL;
+ STACK_OF(X509) *ca_certs = NULL;
+ // There should be no private keys in this file, so we hardcode the password
+ // to "".
+ // TODO(zra): Allow passing a password anyway.
+ int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
+ if (status == 0) {
+ return NULL;
+ }
+
+ ScopedX509 x509(cert);
+ ScopedX509Stack certs(ca_certs);
+
+ // There should be no private key.
+ if (key != NULL) {
+ return NULL;
+ }
+
+ X509_NAME* x509_name = X509_get_subject_name(x509.get());
+ if (x509_name == NULL) {
+ return NULL;
+ }
+
+ x509_name = X509_NAME_dup(x509_name);
+ if (x509_name == NULL) {
+ return NULL;
+ }
+
+ sk_X509_NAME_push(result.get(), x509_name);
+
+ while (true) {
+ ScopedX509 ca(sk_X509_shift(certs.get()));
+ if (ca.get() == NULL) {
+ break;
+ }
+
+ X509_NAME* x509_name = X509_get_subject_name(ca.get());
+ if (x509_name == NULL) {
+ return NULL;
+ }
+
+ x509_name = X509_NAME_dup(x509_name);
+ if (x509_name == NULL) {
+ return NULL;
+ }
+
+ sk_X509_NAME_push(result.get(), x509_name);
+ }
+
+ return result.release();
+}
+
+
+static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) {
+ ScopedX509NAMEStack result(sk_X509_NAME_new_null());
+ if (result.get() == NULL) {
return NULL;
}
while (true) {
- X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- if (x509 == NULL) {
+ ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL));
+ if (x509.get() == NULL) {
break;
}
- X509_NAME* x509_name = X509_get_subject_name(x509);
+ X509_NAME* x509_name = X509_get_subject_name(x509.get());
if (x509_name == NULL) {
- sk_X509_NAME_pop_free(result, X509_NAME_free);
- X509_free(x509);
return NULL;
}
// Duplicate the name to put it on the stack.
x509_name = X509_NAME_dup(x509_name);
if (x509_name == NULL) {
- sk_X509_NAME_pop_free(result, X509_NAME_free);
- X509_free(x509);
return NULL;
}
- sk_X509_NAME_push(result, x509_name);
- X509_free(x509);
+ sk_X509_NAME_push(result.get(), x509_name);
+ }
+
+ uint32_t err = ERR_peek_last_error();
+ if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
+ (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
+ // Some real error happened.
+ return NULL;
}
+ return result.release();
+}
+
+
+static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
+ STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio);
+ uint32_t err = ERR_peek_last_error();
+ if ((result == NULL) &&
+ (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+ ERR_clear_error();
+ BIO_reset(bio);
+ result = GetCertificateNamesPKCS12(bio);
+ } else if (result != NULL) {
+ // The PEM file was successfully parsed.
+ ERR_clear_error();
+ }
return result;
}
@@ -643,7 +946,7 @@ void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
STACK_OF(X509_NAME)* certificate_names;
{
- MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+ ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
certificate_names = GetCertificateNames(bio.bio());
}
« no previous file with comments | « CHANGELOG.md ('k') | sdk/lib/io/security_context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698