Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/base/x509_util.h" | |
| 6 #include "net/base/x509_util_nss.h" | |
|
wtc
2011/10/17 19:09:27
If we follow the Style Guide strictly, only "net/b
| |
| 7 | |
| 8 #include "base/debug/leak_annotations.h" //XXX | |
|
wtc
2011/10/17 19:09:27
Can you remove the "//XXX" comment?
mattm
2011/10/17 22:54:19
Done.
| |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/memory/singleton.h" | |
| 12 #include "crypto/nss_util.h" | |
| 13 #include "crypto/nss_util_internal.h" | |
| 14 #include "crypto/rsa_private_key.h" | |
| 15 #include "crypto/scoped_nss_types.h" | |
| 16 | |
| 17 #include <cert.h> | |
| 18 #include <cryptohi.h> | |
| 19 #include <pk11pub.h> | |
| 20 #include <prerror.h> | |
| 21 #include <secmod.h> | |
| 22 #include <secport.h> | |
|
wtc
2011/10/17 19:09:27
These NSS headers are considered system headers (t
mattm
2011/10/17 22:54:19
Done.
| |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 class ObCertOIDWrapper { | |
| 27 public: | |
| 28 static ObCertOIDWrapper* GetInstance() { | |
| 29 // Instantiated as a leaky singleton to allow the singleton to be | |
| 30 // constructed on a worker thead that is not joined when a process | |
| 31 // shuts down. | |
| 32 return Singleton<ObCertOIDWrapper, | |
| 33 LeakySingletonTraits<ObCertOIDWrapper> >::get(); | |
| 34 } | |
| 35 | |
| 36 SECOidTag ob_cert_oid_tag() const { | |
| 37 return ob_cert_oid_tag_; | |
| 38 } | |
| 39 | |
| 40 private: | |
| 41 friend struct DefaultSingletonTraits<ObCertOIDWrapper>; | |
| 42 | |
| 43 ObCertOIDWrapper(); | |
| 44 | |
| 45 SECOidTag ob_cert_oid_tag_; | |
| 46 | |
| 47 DISALLOW_COPY_AND_ASSIGN(ObCertOIDWrapper); | |
| 48 }; | |
| 49 | |
| 50 ObCertOIDWrapper::ObCertOIDWrapper(): ob_cert_oid_tag_(SEC_OID_UNKNOWN) { | |
| 51 // 1.3.6.1.4.1.11129.2.1.6 | |
| 52 // (iso.org.dod.internet.private.enterprises.google.googleSecurity. | |
| 53 // certificateExtensions.originBoundCertificate) | |
| 54 static const uint8 kObCertOID[] = { | |
| 55 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x06 | |
| 56 }; | |
| 57 SECOidData oid_data; | |
| 58 memset(&oid_data, 0, sizeof(oid_data)); | |
| 59 oid_data.oid.data = const_cast<uint8*>(kObCertOID); | |
| 60 oid_data.oid.len = sizeof(kObCertOID); | |
| 61 oid_data.offset = SEC_OID_UNKNOWN; | |
| 62 oid_data.desc = "Origin Bound Certificate"; | |
| 63 oid_data.mechanism = CKM_INVALID_MECHANISM; | |
| 64 oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION; | |
| 65 ob_cert_oid_tag_ = SECOID_AddEntry(&oid_data); | |
| 66 if (ob_cert_oid_tag_ == SEC_OID_UNKNOWN) | |
| 67 LOG(ERROR) << "OB_CERT OID tag creation failed"; | |
| 68 } | |
| 69 | |
| 70 // Creates a Certificate object that may be passed to the SignCertificate | |
| 71 // method to generate an X509 certificate. | |
| 72 // Returns NULL if an error is encountered in the certificate creation | |
| 73 // process. | |
| 74 // Caller responsible for freeing returned certificate object. | |
| 75 CERTCertificate* CreateCertificate( | |
| 76 SECKEYPublicKeyStr* public_key, | |
|
wtc
2011/10/17 19:09:27
Search for "SECKEYPublicKeyStr" and "SECKEYPrivate
mattm
2011/10/17 22:54:19
Done.
| |
| 77 const std::string& subject, | |
| 78 uint32 serial_number, | |
| 79 base::TimeDelta valid_duration) { | |
| 80 // Create info about public key. | |
| 81 CERTSubjectPublicKeyInfo* spki = | |
| 82 SECKEY_CreateSubjectPublicKeyInfo(public_key); | |
| 83 if (!spki) | |
| 84 return NULL; | |
| 85 | |
| 86 // Create the certificate request. | |
| 87 CERTName* subject_name = | |
| 88 CERT_AsciiToName(const_cast<char*>(subject.c_str())); | |
| 89 CERTCertificateRequest* cert_request = | |
| 90 CERT_CreateCertificateRequest(subject_name, spki, NULL); | |
| 91 SECKEY_DestroySubjectPublicKeyInfo(spki); | |
| 92 | |
| 93 if (!cert_request) { | |
| 94 PRErrorCode prerr = PR_GetError(); | |
| 95 LOG(ERROR) << "Failed to create certificate request: " << prerr; | |
| 96 CERT_DestroyName(subject_name); | |
| 97 return NULL; | |
| 98 } | |
| 99 | |
| 100 PRTime now = PR_Now(); | |
| 101 PRTime not_after = now + valid_duration.InMicroseconds(); | |
| 102 | |
| 103 // Note that the time is now in micro-second unit. | |
| 104 CERTValidity* validity = CERT_CreateValidity(now, not_after); | |
| 105 CERTCertificate* cert = CERT_CreateCertificate(serial_number, subject_name, | |
| 106 validity, cert_request); | |
| 107 if (!cert) { | |
| 108 PRErrorCode prerr = PR_GetError(); | |
| 109 LOG(ERROR) << "Failed to create certificate: " << prerr; | |
| 110 } | |
| 111 | |
| 112 // Cleanup for resources used to generate the cert. | |
| 113 CERT_DestroyName(subject_name); | |
| 114 CERT_DestroyValidity(validity); | |
| 115 CERT_DestroyCertificateRequest(cert_request); | |
| 116 | |
| 117 return cert; | |
| 118 } | |
| 119 | |
| 120 // Signs a certificate object, with |key| generating a new X509Certificate | |
| 121 // and destroying the passed certificate object (even when NULL is returned). | |
| 122 // The logic of this method references SignCert() in NSS utility certutil: | |
| 123 // http://mxr.mozilla.org/security/ident?i=SignCert. | |
| 124 // Returns true on success or false if an error is encountered in the | |
| 125 // certificate signing process. | |
| 126 bool SignCertificate( | |
| 127 CERTCertificate* cert, | |
| 128 SECKEYPrivateKeyStr* key) { | |
| 129 // |arena| is used to encode the cert. | |
| 130 PLArenaPool* arena = cert->arena; | |
| 131 SECOidTag algo_id = SEC_GetSignatureAlgorithmOidTag(key->keyType, | |
| 132 SEC_OID_SHA1); | |
| 133 if (algo_id == SEC_OID_UNKNOWN) | |
| 134 return false; | |
| 135 | |
| 136 SECStatus rv = SECOID_SetAlgorithmID(arena, &cert->signature, algo_id, 0); | |
| 137 if (rv != SECSuccess) | |
| 138 return false; | |
| 139 | |
| 140 // Generate a cert of version 3. | |
| 141 *(cert->version.data) = 2; | |
| 142 cert->version.len = 1; | |
| 143 | |
| 144 SECItem der; | |
| 145 der.len = 0; | |
| 146 der.data = NULL; | |
| 147 | |
| 148 // Use ASN1 DER to encode the cert. | |
| 149 void* encode_result = SEC_ASN1EncodeItem( | |
| 150 arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); | |
| 151 if (!encode_result) | |
| 152 return false; | |
| 153 | |
| 154 // Allocate space to contain the signed cert. | |
| 155 SECItem* result = SECITEM_AllocItem(arena, NULL, 0); | |
| 156 if (!result) | |
| 157 return false; | |
| 158 | |
| 159 // Sign the ASN1 encoded cert and save it to |result|. | |
| 160 rv = SEC_DerSignData(arena, result, der.data, der.len, key, algo_id); | |
| 161 if (rv != SECSuccess) | |
| 162 return false; | |
| 163 | |
| 164 // Save the signed result to the cert. | |
| 165 cert->derCert = *result; | |
| 166 | |
| 167 return true; | |
| 168 } | |
| 169 | |
| 170 } // namespace | |
| 171 | |
| 172 namespace net { | |
| 173 | |
| 174 namespace x509_util { | |
| 175 | |
| 176 CERTCertificate* CreateSelfSignedCert( | |
| 177 SECKEYPublicKeyStr* public_key, | |
| 178 SECKEYPrivateKeyStr* key, | |
| 179 const std::string& subject, | |
| 180 uint32 serial_number, | |
| 181 base::TimeDelta valid_duration) { | |
| 182 CERTCertificate* cert = CreateCertificate(public_key, | |
| 183 subject, | |
| 184 serial_number, | |
| 185 valid_duration); | |
| 186 if (!cert) | |
| 187 return NULL; | |
| 188 | |
| 189 if (SignCertificate(cert, key)) | |
| 190 return cert; | |
| 191 | |
| 192 CERT_DestroyCertificate(cert); | |
| 193 return NULL; | |
|
wtc
2011/10/17 19:09:27
Nit: let's rewrite lines 189-193 as follows:
if
mattm
2011/10/17 22:54:19
Done.
| |
| 194 } | |
| 195 | |
| 196 bool CreateOriginBoundCert( | |
| 197 crypto::RSAPrivateKey* key, | |
| 198 const std::string& origin, | |
| 199 uint32 serial_number, | |
| 200 base::TimeDelta valid_duration, | |
| 201 std::string* der_cert) { | |
| 202 DCHECK(key); | |
| 203 | |
| 204 SECKEYPublicKeyStr* public_key; | |
| 205 SECKEYPrivateKeyStr* private_key; | |
| 206 #if defined(USE_NSS) | |
| 207 public_key = key->public_key(); | |
| 208 private_key = key->key(); | |
| 209 #else | |
| 210 crypto::ScopedSECKEYPublicKey public_key_holder; | |
| 211 crypto::ScopedSECKEYPrivateKey private_key_holder; | |
|
wtc
2011/10/17 19:09:27
Nit: our convention is to name this kind of Scoped
mattm
2011/10/17 22:54:19
Done.
| |
| 212 { | |
| 213 // Based on the NSS RSAPrivateKey::CreateFromPrivateKeyInfoWithParams. | |
| 214 // This method currently leaks some memory. | |
| 215 // See http://crbug.com/34742. | |
| 216 ANNOTATE_SCOPED_MEMORY_LEAK; | |
| 217 crypto::EnsureNSSInit(); | |
| 218 | |
| 219 std::vector<uint8> key_data; | |
| 220 key->ExportPrivateKey(&key_data); | |
| 221 | |
| 222 crypto::ScopedPK11Slot slot(crypto::GetPrivateNSSKeySlot()); | |
| 223 if (!slot.get()) | |
| 224 return NULL; | |
| 225 | |
| 226 SECItem der_private_key_info; | |
| 227 der_private_key_info.data = const_cast<unsigned char*>(&key_data.front()); | |
|
wtc
2011/10/17 19:09:27
Nit: &key_data.front() => &key_data[0]
mattm
2011/10/17 22:54:19
Done.
| |
| 228 der_private_key_info.len = key_data.size(); | |
| 229 // Allow the private key to be used for key unwrapping, data decryption, | |
| 230 // and signature generation. | |
| 231 const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | | |
| 232 KU_DIGITAL_SIGNATURE; | |
|
wtc
2011/10/17 19:09:27
Nit: align this with KU_KEY_ENCIPHERMENT on the pr
mattm
2011/10/17 22:54:19
Done.
| |
| 233 SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( | |
| 234 slot.get(), &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE, | |
| 235 key_usage, &private_key, NULL); | |
| 236 private_key_holder.reset(private_key); | |
| 237 if (rv != SECSuccess) { | |
| 238 NOTREACHED(); | |
| 239 return NULL; | |
| 240 } | |
| 241 | |
| 242 public_key = SECKEY_ConvertToPublicKey(private_key); | |
| 243 if (!public_key) { | |
| 244 NOTREACHED(); | |
| 245 return NULL; | |
| 246 } | |
| 247 public_key_holder.reset(public_key); | |
| 248 } | |
| 249 #endif | |
| 250 | |
| 251 CERTCertificate* cert = CreateCertificate(public_key, | |
| 252 "CN=anonymous.invalid", | |
| 253 serial_number, | |
| 254 valid_duration); | |
| 255 | |
| 256 if (!cert) | |
| 257 return false; | |
| 258 | |
| 259 // Create opaque handle used to add extensions later. | |
| 260 void* cert_handle; | |
| 261 if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { | |
| 262 LOG(ERROR) << "Unable to get opaque handle for adding extensions"; | |
| 263 CERT_DestroyCertificate(cert); | |
| 264 return false; | |
| 265 } | |
| 266 | |
| 267 // Create SECItem for IA5String encoding. | |
| 268 SECItem origin_string_item = { | |
| 269 siAsciiString, | |
| 270 (unsigned char*)origin.data(), | |
| 271 origin.size() | |
| 272 }; | |
| 273 | |
| 274 // IA5Encode and arena allocate SECItem | |
| 275 SECItem* asn1_origin_string = SEC_ASN1EncodeItem( | |
| 276 cert->arena, NULL, &origin_string_item, | |
| 277 SEC_ASN1_GET(SEC_IA5StringTemplate)); | |
| 278 if (asn1_origin_string == NULL) { | |
| 279 LOG(ERROR) << "Unable to get ASN1 encoding for origin in ob_cert extension"; | |
| 280 CERT_DestroyCertificate(cert); | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 // Add the extension to the opaque handle | |
| 285 if (CERT_AddExtension(cert_handle, | |
| 286 ObCertOIDWrapper::GetInstance()->ob_cert_oid_tag(), | |
| 287 asn1_origin_string, | |
| 288 PR_TRUE, PR_TRUE) != SECSuccess){ | |
| 289 LOG(ERROR) << "Unable to add origin bound cert extension to opaque handle"; | |
| 290 CERT_DestroyCertificate(cert); | |
| 291 return false; | |
| 292 } | |
| 293 | |
| 294 // Copy extension into x509 cert | |
| 295 if (CERT_FinishExtensions(cert_handle) != SECSuccess){ | |
| 296 LOG(ERROR) << "Unable to copy extension to X509 cert"; | |
| 297 CERT_DestroyCertificate(cert); | |
| 298 return false; | |
| 299 } | |
| 300 | |
| 301 if (SignCertificate(cert, private_key)) { | |
| 302 DCHECK(cert->derCert.len); | |
| 303 // XXX copied from X509Certificate::GetDEREncoded | |
| 304 der_cert->clear(); | |
| 305 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), | |
| 306 cert->derCert.len); | |
| 307 CERT_DestroyCertificate(cert); | |
| 308 return true; | |
| 309 } | |
| 310 | |
| 311 CERT_DestroyCertificate(cert); | |
| 312 return false; | |
| 313 } | |
| 314 | |
| 315 } // namespace x509_util | |
| 316 | |
| 317 } // namespace net | |
| OLD | NEW |