summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/media/webrtc_identity_store_unittest.cc5
-rw-r--r--net/cert/x509_util.h7
-rw-r--r--net/cert/x509_util_nss.cc1
-rw-r--r--net/cert/x509_util_openssl.cc95
-rw-r--r--net/cert/x509_util_unittest.cc2
5 files changed, 97 insertions, 13 deletions
diff --git a/content/browser/media/webrtc_identity_store_unittest.cc b/content/browser/media/webrtc_identity_store_unittest.cc
index 129fa8d..85bd18f 100644
--- a/content/browser/media/webrtc_identity_store_unittest.cc
+++ b/content/browser/media/webrtc_identity_store_unittest.cc
@@ -15,10 +15,6 @@
namespace content {
-// TODO(jiayl): the tests fail on Android since the openssl version of
-// CreateSelfSignedCert is not implemented.
-#if !defined(OS_ANDROID)
-
static const char* kFakeOrigin = "http://foo.com";
static const char* kFakeIdentityName1 = "name1";
static const char* kFakeIdentityName2 = "name2";
@@ -347,5 +343,4 @@ TEST_F(WebRTCIdentityStoreTest, IdentityPersistentAcrossRestart) {
EXPECT_EQ(key_1, key_2);
}
-#endif
} // namespace content
diff --git a/net/cert/x509_util.h b/net/cert/x509_util.h
index 8a6bae2..513878d 100644
--- a/net/cert/x509_util.h
+++ b/net/cert/x509_util.h
@@ -50,10 +50,9 @@ NET_EXPORT_PRIVATE bool CreateDomainBoundCertEC(
// The certificate is signed by the private key in |key|. The hashing
// algorithm for the signature is SHA-1.
//
-// |subject| is a distinguished name defined in RFC4514.
-//
-// An example:
-// CN=Michael Wong,O=FooBar Corporation,DC=foobar,DC=com
+// |subject| is a distinguished name defined in RFC4514 with _only_ a CN
+// component, as in:
+// CN=Michael Wong
//
// SECURITY WARNING
//
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc
index f8fbd6f..de09b95 100644
--- a/net/cert/x509_util_nss.cc
+++ b/net/cert/x509_util_nss.cc
@@ -246,6 +246,7 @@ bool CreateSelfSignedCert(crypto::RSAPrivateKey* key,
base::Time not_valid_after,
std::string* der_cert) {
DCHECK(key);
+ DCHECK(!strncmp(subject.c_str(), "CN=", 3U));
CERTCertificate* cert = CreateCertificate(key->public_key(),
subject,
serial_number,
diff --git a/net/cert/x509_util_openssl.cc b/net/cert/x509_util_openssl.cc
index e4dec99..89c5394 100644
--- a/net/cert/x509_util_openssl.cc
+++ b/net/cert/x509_util_openssl.cc
@@ -9,6 +9,8 @@
#include "base/logging.h"
#include "base/strings/string_piece.h"
+#include "crypto/openssl_util.h"
+#include "crypto/rsa_private_key.h"
#include "net/cert/x509_cert_types.h"
namespace net {
@@ -65,8 +67,97 @@ bool CreateSelfSignedCert(crypto::RSAPrivateKey* key,
base::Time not_valid_before,
base::Time not_valid_after,
std::string* der_encoded) {
- NOTIMPLEMENTED();
- return false;
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
+ static const char kCommonNamePrefix[] = "CN=";
+ const size_t kCommonNamePrefixLen = sizeof(kCommonNamePrefix) - 1;
+
+ // Put the serial number into an OpenSSL-friendly object.
+ crypto::ScopedOpenSSL<ASN1_INTEGER, ASN1_INTEGER_free> asn1_serial(
+ ASN1_INTEGER_new());
+ if (!asn1_serial.get() ||
+ !ASN1_INTEGER_set(asn1_serial.get(), static_cast<long>(serial_number))) {
+ LOG(ERROR) << "Invalid serial number " << serial_number;
+ return false;
+ }
+
+ // Do the same for the time stamps.
+ crypto::ScopedOpenSSL<ASN1_TIME, ASN1_TIME_free> asn1_not_before_time(
+ ASN1_TIME_set(NULL, not_valid_before.ToTimeT()));
+ if (!asn1_not_before_time.get()) {
+ LOG(ERROR) << "Invalid not_valid_before time: "
+ << not_valid_before.ToTimeT();
+ return false;
+ }
+
+ crypto::ScopedOpenSSL<ASN1_TIME, ASN1_TIME_free> asn1_not_after_time(
+ ASN1_TIME_set(NULL, not_valid_after.ToTimeT()));
+ if (!asn1_not_after_time.get()) {
+ LOG(ERROR) << "Invalid not_valid_after time: " << not_valid_after.ToTimeT();
+ return false;
+ }
+
+ // Because |common_name| only contains a common name and starts with 'CN=',
+ // there is no need for a full RFC 2253 parser here. Do some sanity checks
+ // though.
+ if (common_name.size() < kCommonNamePrefixLen ||
+ strncmp(common_name.c_str(), kCommonNamePrefix, kCommonNamePrefixLen)) {
+ LOG(ERROR) << "Common name must begin with " << kCommonNamePrefix;
+ return false;
+ }
+ if (common_name.size() > INT_MAX) {
+ LOG(ERROR) << "Common name too long";
+ return false;
+ }
+ unsigned char* common_name_str =
+ reinterpret_cast<unsigned char*>(const_cast<char*>(common_name.data())) +
+ kCommonNamePrefixLen;
+ int common_name_len =
+ static_cast<int>(common_name.size()) - kCommonNamePrefixLen;
+
+ crypto::ScopedOpenSSL<X509_NAME, X509_NAME_free> name(X509_NAME_new());
+ if (!name.get() || !X509_NAME_add_entry_by_NID(name.get(),
+ NID_commonName,
+ MBSTRING_ASC,
+ common_name_str,
+ common_name_len,
+ -1,
+ 0)) {
+ LOG(ERROR) << "Can't parse common name: " << common_name.c_str();
+ return false;
+ }
+
+ // Now create certificate and populate it.
+ crypto::ScopedOpenSSL<X509, X509_free> cert(X509_new());
+ if (!cert.get() || !X509_set_version(cert.get(), 2L) /* i.e. version 3 */ ||
+ !X509_set_pubkey(cert.get(), key->key()) ||
+ !X509_set_serialNumber(cert.get(), asn1_serial.get()) ||
+ !X509_set_notBefore(cert.get(), asn1_not_before_time.get()) ||
+ !X509_set_notAfter(cert.get(), asn1_not_after_time.get()) ||
+ !X509_set_subject_name(cert.get(), name.get()) ||
+ !X509_set_issuer_name(cert.get(), name.get())) {
+ LOG(ERROR) << "Could not create certificate";
+ return false;
+ }
+
+ // Sign it with the private key.
+ if (!X509_sign(cert.get(), key->key(), EVP_sha1())) {
+ LOG(ERROR) << "Could not sign certificate with key.";
+ return false;
+ }
+
+ // Convert it into a DER-encoded string copied to |der_encoded|.
+ int der_data_length = i2d_X509(cert.get(), NULL);
+ if (der_data_length < 0)
+ return false;
+
+ der_encoded->resize(static_cast<size_t>(der_data_length));
+ unsigned char* der_data =
+ reinterpret_cast<unsigned char*>(&(*der_encoded)[0]);
+
+ if (i2d_X509(cert.get(), &der_data) < 0)
+ return false;
+
+ return true;
}
bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name,
diff --git a/net/cert/x509_util_unittest.cc b/net/cert/x509_util_unittest.cc
index cc13d96..8fa24d2 100644
--- a/net/cert/x509_util_unittest.cc
+++ b/net/cert/x509_util_unittest.cc
@@ -52,7 +52,6 @@ TEST(X509UtilTest, SortClientCertificates) {
ASSERT_FALSE(certs[5].get());
}
-#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
// This test creates a self-signed cert from a private key and then verify the
// content of the certificate.
TEST(X509UtilTest, CreateSelfSigned) {
@@ -183,7 +182,6 @@ TEST(X509UtilTest, CreateSelfSigned) {
EXPECT_EQ("subject", cert->subject().GetDisplayName());
EXPECT_FALSE(cert->HasExpired());
}
-#endif
} // namespace x509_util