Index: net/base/x509_certificate_nss.cc |
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc |
index 7224020cb44e528318c204f10f3d6e70ff0dced2..f35c7a2426abf4915440d112ba416520b40327d9 100644 |
--- a/net/base/x509_certificate_nss.cc |
+++ b/net/base/x509_certificate_nss.cc |
@@ -18,6 +18,7 @@ |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
+#include "base/memory/singleton.h" |
#include "base/pickle.h" |
#include "base/time.h" |
#include "crypto/nss_util.h" |
@@ -31,6 +32,48 @@ namespace net { |
namespace { |
+class ObCertOIDWrapper { |
+ public: |
+ static ObCertOIDWrapper* GetInstance() { |
+ return Singleton<ObCertOIDWrapper, |
+ LeakySingletonTraits<ObCertOIDWrapper> >::get(); |
+ } |
wtc
2011/08/23 01:32:21
I would format this method as follows:
static O
mdietz
2011/08/23 20:52:56
Done.
|
+ |
+ SECOidTag ob_cert_oid_tag() const { |
+ return ob_cert_oid_tag_; |
+ } |
+ |
+ private: |
+ SECOidTag ob_cert_oid_tag_; |
+ |
+ ObCertOIDWrapper(); |
+ |
+ friend struct DefaultSingletonTraits<ObCertOIDWrapper>; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ObCertOIDWrapper); |
+}; |
wtc
2011/08/23 01:32:21
Please fix the indentation in this class.
"public
mdietz
2011/08/23 20:52:56
Done.
|
+ |
+ObCertOIDWrapper::ObCertOIDWrapper() |
+ : ob_cert_oid_tag_(SEC_OID_UNKNOWN) { |
wtc
2011/08/23 01:32:21
The Style Guide recommends indenting the colon of
mdietz
2011/08/23 20:52:56
Done.
|
+ // 1.3.6.1.4.1.11129.2.1.6 |
+ // (iso.org.dod.internet.private.enterprises.google.googleSecurity. |
+ // certificateExtensions.originBoundCertificate) |
+ static const uint8 kObCertOID[] = { |
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x06 |
+ }; |
+ SECOidData oid_data; |
+ memset(&oid_data, 0, sizeof(oid_data)); |
+ oid_data.oid.data = const_cast<uint8*>(kObCertOID); |
+ oid_data.oid.len = sizeof(kObCertOID); |
+ oid_data.offset = SEC_OID_UNKNOWN; |
+ oid_data.desc = "Origin Bound Certificate"; |
+ oid_data.mechanism = CKM_INVALID_MECHANISM; |
+ oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION; |
+ ob_cert_oid_tag_ = SECOID_AddEntry(&oid_data); |
+ if (ob_cert_oid_tag_ == SEC_OID_UNKNOWN) |
+ LOG(ERROR) << "OB_CERT OID tag creation failed"; |
+} |
+ |
class ScopedCERTCertificatePolicies { |
public: |
explicit ScopedCERTCertificatePolicies(CERTCertificatePolicies* policies) |
@@ -623,14 +666,16 @@ void X509Certificate::Initialize() { |
serial_number_ = serial_number_.substr(1, serial_number_.size() - 1); |
} |
-// static |
-X509Certificate* X509Certificate::CreateSelfSigned( |
+// Creates a Certificate object that may be passed to the SignCertificate |
+// method to generate an X509 certificate. |
+// Returns NULL if an error is encountered in the certificate creation |
+// process. |
+// Caller responsible for freeing returned certificate object. |
+static CERTCertificate* CreateCertificate( |
crypto::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()); |
@@ -668,12 +713,24 @@ X509Certificate* X509Certificate::CreateSelfSigned( |
CERT_DestroyValidity(validity); |
CERT_DestroyCertificateRequest(cert_request); |
- if (!cert) |
- return NULL; |
- |
- // Sign the cert here. The logic of this method references SignCert() in NSS |
- // utility certutil: http://mxr.mozilla.org/security/ident?i=SignCert. |
+ return cert; |
+} |
+// Signs a certificate object, with |key| generating a new X509Certificate |
+// and destroying the passed certificate object (even when NULL is returned). |
+// The logic of this method references SignCert() in NSS utility certutil: |
+// http://mxr.mozilla.org/security/ident?i=SignCert. |
+// Returns NULL if an error is encountered in the certificate signing |
+// process. |
+// Caller responsible for freeing returned X509Certificate object. |
+// |
+// TODO: change this function to return |
+// a success/failure status, and not create an X509Certificate |
+// object, and not destroy |cert| on failure. Let the caller |
+// create the X509Certificate object and destroy |cert|. |
+static X509Certificate* SignCertificate( |
+ CERTCertificate* cert, |
+ crypto::RSAPrivateKey* key) { |
// |arena| is used to encode the cert. |
PRArenaPool* arena = cert->arena; |
SECOidTag algo_id = SEC_GetSignatureAlgorithmOidTag(key->key()->keyType, |
@@ -722,11 +779,91 @@ X509Certificate* X509Certificate::CreateSelfSigned( |
// Save the signed result to the cert. |
cert->derCert = *result; |
- X509Certificate* x509_cert = CreateFromHandle(cert, OSCertHandles()); |
+ X509Certificate* x509_cert = |
+ X509Certificate::CreateFromHandle(cert, X509Certificate::OSCertHandles()); |
wtc
2011/08/23 01:32:21
Nit: indent this line by four spaces.
mdietz
2011/08/23 20:52:56
Done.
|
CERT_DestroyCertificate(cert); |
return x509_cert; |
} |
+X509Certificate* X509Certificate::CreateSelfSigned( |
wtc
2011/08/23 01:32:21
Resurrect the "// static" comment for this method
mdietz
2011/08/23 20:52:56
Done.
|
+ crypto::RSAPrivateKey* key, |
+ const std::string& subject, |
+ uint32 serial_number, |
+ base::TimeDelta valid_duration) { |
+ DCHECK(key); |
+ |
+ CERTCertificate* cert = CreateCertificate(key, |
+ subject, |
+ serial_number, |
+ valid_duration); |
+ |
+ if(!cert) |
wtc
2011/08/23 01:32:21
Add a space after "if" here and on line 820 below.
mdietz
2011/08/23 20:52:56
Done.
|
+ return NULL; |
+ |
+ X509Certificate* x509_cert = SignCertificate(cert, key); |
+ |
+ return x509_cert; |
+} |
+ |
+X509Certificate* X509Certificate::CreateOriginBound( |
+ crypto::RSAPrivateKey* key, |
+ const std::string& origin, |
+ uint32 serial_number, |
+ base::TimeDelta valid_duration) { |
+ DCHECK(key); |
+ |
+ CERTCertificate* cert = CreateCertificate(key, |
+ "CN=anonymous.invalid", |
+ serial_number, |
+ valid_duration); |
+ |
+ if(!cert) |
+ return NULL; |
+ |
+ // Create opaque handle used to add extensions later. |
+ void* cert_handle; |
+ if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { |
+ LOG(ERROR) << "Unable to get opaque handle for adding extensions"; |
+ return NULL; |
+ } |
+ |
+ // Create SECItem for IA5String encoding. |
+ SECItem origin_string_item = { |
+ siAsciiString, |
+ (unsigned char*)origin.data(), |
+ origin.size() |
+ }; |
+ |
+ // IA5Encode and arena allocate SECItem |
+ SECItem* asn1_origin_string = SEC_ASN1EncodeItem( |
+ cert->arena, NULL, &origin_string_item, |
+ SEC_ASN1_GET(SEC_IA5StringTemplate)); |
+ if (asn1_origin_string == NULL) { |
+ LOG(ERROR) << "Unable to get ASN1 encoding for origin in ob_cert extension"; |
+ return NULL; |
+ } |
+ |
+ // Add the extension to the opaque handle |
+ if (CERT_AddExtension(cert_handle, |
+ ObCertOIDWrapper::GetInstance()->ob_cert_oid_tag(), |
+ asn1_origin_string, |
+ PR_TRUE, PR_TRUE) |
+ != SECSuccess){ |
wtc
2011/08/23 01:32:21
Nit: move this to the previous line.
mdietz
2011/08/23 20:52:56
Done.
|
+ LOG(ERROR) << "Unable to add origin bound cert extension to opaque handle"; |
+ return NULL; |
+ } |
+ |
+ // Copy extension into x509 cert |
+ if (CERT_FinishExtensions(cert_handle) != SECSuccess){ |
+ LOG(ERROR) << "Unable to copy extension to X509 cert"; |
+ return NULL; |
+ } |
+ |
+ X509Certificate* x509_cert = SignCertificate(cert, key); |
+ |
+ return x509_cert; |
+} |
+ |
void X509Certificate::GetSubjectAltName( |
std::vector<std::string>* dns_names, |
std::vector<std::string>* ip_addrs) const { |