Index: net/base/x509_certificate_nss.cc |
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc |
index 945e7cfc681781db8db33cdbf0333d5b49467e4a..5061b8c3299909246ee2cddcc923e518f8ac13fc 100644 |
--- a/net/base/x509_certificate_nss.cc |
+++ b/net/base/x509_certificate_nss.cc |
@@ -755,6 +755,178 @@ X509Certificate* X509Certificate::CreateSelfSigned( |
return x509_cert; |
} |
+// static |
+X509Certificate* X509Certificate::CreateOriginBound( |
wtc
2011/08/04 00:37:53
The CreateOriginBound function is identical to Cre
mdietz
2011/08/18 00:02:45
The create origin bound code block in the middle c
|
+ crypto::RSAPrivateKey* key, |
+ const std::string& subject, |
+ const std::string& origin, |
+ 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); |
+ |
+ if (!cert) |
+ return NULL; |
+ |
+ /* Configure X509 library to handle the OB_CERT X509 Extension OID */ |
wtc
2011/08/04 00:37:53
Use the C++ comment delimiter //.
The Style Guide
mdietz
2011/08/18 00:02:45
Done.
|
+ static bool ob_cert_oid_tag_defined; |
+ static SECOidTag ob_cert_oid_tag; |
+ |
+ if (!ob_cert_oid_tag_defined) { |
wtc
2011/08/04 00:37:53
Chrome has a Singleton and LazyInstance class to d
mdietz
2011/08/18 00:02:45
Implemented as a Sinlgeton wrapper around a SECOid
|
+ // It's harmless if multiple threads enter this block concurrently. |
+ static const uint8 kObCertOID[] = |
+ // 1.3.6.1.4.1.11129.2.1.6 |
+ // (iso.org.dod.internet.private.enterprises.google.googleSecurity. |
+ // certificateExtensions.originBoundCertificate) |
+ {0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x06}; |
wtc
2011/08/04 00:37:53
I would format this as follows:
static const uin
mdietz
2011/08/18 00:02:45
Done.
mdietz
2011/08/18 00:02:45
Done.
|
+ SECOidData oid_data; |
+ memset(&oid_data, 0, sizeof(oid_data)); |
+ oid_data.oid.data = const_cast<uint8*>(kObCertOID); |
+ oid_data.oid.len = sizeof(kObCertOID); |
wtc
2011/08/04 00:37:53
Add
oid_data.offset = SEC_OID_UNKNOWN;
This is
mdietz
2011/08/18 00:02:45
Done.
|
+ oid_data.desc = "Origin Bound Certificate"; |
wtc
2011/08/04 00:37:53
Add
oid_data.mechanism = CKM_INVALID_MECHANISM;
mdietz
2011/08/18 00:02:45
Done.
|
+ oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION; |
+ ob_cert_oid_tag = SECOID_AddEntry(&oid_data); |
+ DCHECK_NE(SEC_OID_UNKNOWN, ob_cert_oid_tag); |
wtc
2011/08/04 00:37:53
Remove this DCHECK_NE because it has proper error
mdietz
2011/08/18 00:02:45
Done.
|
+ if(ob_cert_oid_tag == SEC_OID_UNKNOWN) { |
+ LOG(ERROR) << "OB_CERT OID tag creation failed"; |
+ return NULL; |
+ } |
+ ob_cert_oid_tag_defined = true; |
+ } |
+ |
+ SECStatus ok; |
+ |
+ // Create opaque handle to add extensions |
+ void* cert_handle; |
+ if((cert_handle = CERT_StartCertExtensions(cert)) == NULL){ |
wtc
2011/08/04 00:37:53
Add a space after "if".
Add a space before the op
mdietz
2011/08/18 00:02:45
Done.
|
+ LOG(ERROR) << "Unable to get opaque handle for adding extensions"; |
+ return NULL; |
+ } |
+ |
+ // Create stack allocated SECItem for IA5String encoding |
+ SECItem origin_string_item = {siAsciiString, |
+ (unsigned char*)origin.c_str(), |
+ origin.size()+1}; |
wtc
2011/08/04 00:37:53
The terminating null should not be included.
I wo
mdietz
2011/08/18 00:02:45
Done.
Note to self: Apply same to unittest.
|
+ |
+ // IA5Encode and arena allocate SECItem |
+ SECItem *asn1_origin_string; |
wtc
2011/08/04 00:37:53
Put * next to the type.
|
+ if((asn1_origin_string = SEC_ASN1EncodeItem( |
+ cert->arena, |
+ NULL, |
+ &origin_string_item, |
+ SEC_ASN1_GET(SEC_IA5StringTemplate))) |
wtc
2011/08/04 00:37:53
Indent the wrapped parameters by four spaces.
mdietz
2011/08/18 00:02:45
Done.
This might exceed 80 lines on the last line
|
+ == NULL){ |
+ LOG(ERROR) << "Unable to get ASN1 encoding for origin in ob_cert extension"; |
+ return NULL; |
+ } |
+ |
+ // Add the extension to the opaque handle |
+ if((ok = CERT_AddExtension(cert_handle, ob_cert_oid_tag, asn1_origin_string, |
+ PR_TRUE, PR_TRUE)) |
+ != SECSuccess){ |
+ LOG(ERROR) << "Unable to add origin bound cert extension to opaque handle"; |
+ return NULL; |
+ } |
+ |
+ // Copy extension into x509 cert |
+ if((ok = CERT_FinishExtensions(cert_handle)) != SECSuccess){ |
+ LOG(ERROR) << "Unable to copy extension to X509 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. |
+ |
+ // |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::GetDNSNames(std::vector<std::string>* dns_names) const { |
dns_names->clear(); |