diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-17 21:13:16 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-17 21:13:16 +0000 |
commit | 56f2ec39bd6be763b9493eff17bf4a359b97be68 (patch) | |
tree | 0ca82de141503d2f2ff749e7621b3e72e04582c2 /net | |
parent | 0e043d1a747de34d49b525282929038bb92048dd (diff) | |
download | chromium_src-56f2ec39bd6be763b9493eff17bf4a359b97be68.zip chromium_src-56f2ec39bd6be763b9493eff17bf4a359b97be68.tar.gz chromium_src-56f2ec39bd6be763b9493eff17bf4a359b97be68.tar.bz2 |
Create self signed X509 certificate
In order to run a SSL server certificate and private key is needed. In the case
of Chromoting the first step is to use self signed cert. This change allows to
issue self signed cert. This is only implemented in NSS.
BUG=None
TEST=net_unittests
Review URL: http://codereview.chromium.org/5754001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69573 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/x509_certificate.h | 29 | ||||
-rw-r--r-- | net/base/x509_certificate_nss.cc | 105 | ||||
-rw-r--r-- | net/base/x509_certificate_unittest.cc | 16 |
3 files changed, 150 insertions, 0 deletions
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 89bf476..349a08c 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -36,6 +36,10 @@ struct CERTCertificateStr; class Pickle; +namespace base { +class RSAPrivateKey; +} // namespace base + namespace net { class CertVerifyResult; @@ -148,6 +152,31 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { int length, int format); +#if defined(USE_NSS) + // Create a self-signed certificate containing the public key in |key|. + // Subject, serial number and validity period are given as parameters. + // 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 + // + // SECURUITY WARNING + // + // Using self-signed certificates has the following security risks: + // 1. Encryption without authentication and thus vulnerable to + // man-in-the-middle attacks. + // 2. Self-signed certificates cannot be revoked. + // + // Use this certificate only after the above risks are acknowledged. + static X509Certificate* CreateSelfSigned(base::RSAPrivateKey* key, + const std::string& subject, + uint32 serial_number, + base::TimeDelta valid_duration); +#endif + // Creates a X509Certificate from the ground up. Used by tests that simulate // SSL connections. X509Certificate(const std::string& subject, const std::string& issuer, diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc index 5061238..2962cb5 100644 --- a/net/base/x509_certificate_nss.cc +++ b/net/base/x509_certificate_nss.cc @@ -5,6 +5,8 @@ #include "net/base/x509_certificate.h" #include <cert.h> +#include <cryptohi.h> +#include <keyhi.h> #include <nss.h> #include <pk11pub.h> #include <prerror.h> @@ -14,6 +16,7 @@ #include <sechash.h> #include <sslerr.h> +#include "base/crypto/rsa_private_key.h" #include "base/logging.h" #include "base/pickle.h" #include "base/scoped_ptr.h" @@ -604,6 +607,108 @@ X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, return CreateFromBytes(data, length); } +// static +X509Certificate* X509Certificate::CreateSelfSigned( + base::RSAPrivateKey* key, + const std::string& subject, + uint32 serial_number, + base::TimeDelta valid_duration) { + DCHECK(key); + + // Create info about public key. + CERTSubjectPublicKeyInfo* spki = + SECKEY_CreateSubjectPublicKeyInfo(key->public_key()); + if (!spki) + return NULL; + + // Create the certificate request. + CERTName* subject_name = + CERT_AsciiToName(const_cast<char*>(subject.c_str())); + CERTCertificateRequest* cert_request = + CERT_CreateCertificateRequest(subject_name, spki, NULL); + SECKEY_DestroySubjectPublicKeyInfo(spki); + + if (!cert_request) { + PRErrorCode prerr = PR_GetError(); + LOG(ERROR) << "Failed to create certificate request: " << prerr; + CERT_DestroyName(subject_name); + return NULL; + } + + PRTime now = PR_Now(); + PRTime not_after = now + valid_duration.InMicroseconds(); + + // Note that the time is now in micro-second unit. + CERTValidity* validity = CERT_CreateValidity(now, not_after); + CERTCertificate* cert = CERT_CreateCertificate(serial_number, subject_name, + validity, cert_request); + if (!cert) { + PRErrorCode prerr = PR_GetError(); + LOG(ERROR) << "Failed to create certificate: " << prerr; + } + + // Cleanup for resources used to generate the cert. + CERT_DestroyName(subject_name); + CERT_DestroyValidity(validity); + CERT_DestroyCertificateRequest(cert_request); + + // Sign the cert here. The logic of this method references SignCert() in NSS + // utility certutil: http://mxr.mozilla.org/security/ident?i=SignCert. + + // |arena| is used to encode the cert. + PRArenaPool* arena = cert->arena; + SECOidTag algo_id = SEC_GetSignatureAlgorithmOidTag(key->key()->keyType, + SEC_OID_SHA1); + if (algo_id == SEC_OID_UNKNOWN) { + CERT_DestroyCertificate(cert); + return NULL; + } + + SECStatus rv = SECOID_SetAlgorithmID(arena, &cert->signature, algo_id, 0); + if (rv != SECSuccess) { + CERT_DestroyCertificate(cert); + return NULL; + } + + // Generate a cert of version 3. + *(cert->version.data) = 2; + cert->version.len = 1; + + SECItem der; + der.len = 0; + der.data = NULL; + + // Use ASN1 DER to encode the cert. + void* encode_result = SEC_ASN1EncodeItem( + arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); + if (!encode_result) { + CERT_DestroyCertificate(cert); + return NULL; + } + + // Allocate space to contain the signed cert. + SECItem* result = SECITEM_AllocItem(arena, NULL, 0); + if (!result) { + CERT_DestroyCertificate(cert); + return NULL; + } + + // Sign the ASN1 encoded cert and save it to |result|. + rv = SEC_DerSignData(arena, result, der.data, der.len, key->key(), algo_id); + if (rv != SECSuccess) { + CERT_DestroyCertificate(cert); + return NULL; + } + + // Save the signed result to the cert. + cert->derCert = *result; + + X509Certificate* x509_cert = + CreateFromHandle(cert, SOURCE_LONE_CERT_IMPORT, OSCertHandles()); + CERT_DestroyCertificate(cert); + return x509_cert; +} + void X509Certificate::Persist(Pickle* pickle) { pickle->WriteData(reinterpret_cast<const char*>(cert_handle_->derCert.data), cert_handle_->derCert.len); diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc index b316b12c6..893f849 100644 --- a/net/base/x509_certificate_unittest.cc +++ b/net/base/x509_certificate_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/crypto/rsa_private_key.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/path_service.h" @@ -658,6 +659,21 @@ TEST(X509CertificateTest, IsIssuedBy) { } #endif // defined(OS_MACOSX) +#if defined(USE_NSS) +// CreateSelfSigned() is only implemented using NSS. +// This test creates a signed cert from a private key and then +TEST(X509CertificateTest, CreateSelfSigned) { + scoped_ptr<base::RSAPrivateKey> private_key( + base::RSAPrivateKey::Create(1024)); + scoped_refptr<net::X509Certificate> cert = + net::X509Certificate::CreateSelfSigned( + private_key.get(), "CN=subject", 1, base::TimeDelta::FromDays(1)); + + EXPECT_EQ("subject", cert->subject().GetDisplayName()); + EXPECT_FALSE(cert->HasExpired()); +} +#endif + class X509CertificateParseTest : public testing::TestWithParam<CertificateFormatTestData> { public: |