summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authordigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-18 03:49:47 +0000
committerdigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-18 03:49:47 +0000
commit5d30729bbea9ae61320fc879642393fb051f2ab5 (patch)
tree252a24305397d5785d161854848b9d99816ab337 /net
parent96a0c067d816576735856452608a03bd7e914504 (diff)
downloadchromium_src-5d30729bbea9ae61320fc879642393fb051f2ab5.zip
chromium_src-5d30729bbea9ae61320fc879642393fb051f2ab5.tar.gz
chromium_src-5d30729bbea9ae61320fc879642393fb051f2ab5.tar.bz2
Implement x509_util::CreateSelfSignedCert() for OpenSSL.
This requires a parser for RFC 2253 strings, so add one in "net/cert/x509_util_openssl.h", and an appropriate unit test. BUG=306176 R=rsleevi@chromium.org,phajdan.jr@chromium.org TESTING build/android/test_runner.py gtest -s net_unittests build/android/test_runner.py gtest -s content_unittests Review URL: https://codereview.chromium.org/27096005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229305 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-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
4 files changed, 97 insertions, 8 deletions
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