| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/x509_util.h" | 5 #include "net/base/x509_util.h" |
| 6 #include "net/base/x509_util_nss.h" | 6 #include "net/base/x509_util_nss.h" |
| 7 | 7 |
| 8 #include <cert.h> | 8 #include <cert.h> |
| 9 #include <cryptohi.h> | 9 #include <cryptohi.h> |
| 10 #include <pk11pub.h> | 10 #include <pk11pub.h> |
| 11 #include <prerror.h> | 11 #include <prerror.h> |
| 12 #include <secmod.h> | 12 #include <secmod.h> |
| 13 #include <secport.h> | 13 #include <secport.h> |
| 14 | 14 |
| 15 #include "base/debug/leak_annotations.h" | 15 #include "base/debug/leak_annotations.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
| 18 #include "base/memory/singleton.h" | 18 #include "base/memory/singleton.h" |
| 19 #include "crypto/ec_private_key.h" | 19 #include "crypto/ec_private_key.h" |
| 20 #include "crypto/nss_util.h" | 20 #include "crypto/nss_util.h" |
| 21 #include "crypto/nss_util_internal.h" | 21 #include "crypto/nss_util_internal.h" |
| 22 #include "crypto/scoped_nss_types.h" | 22 #include "crypto/scoped_nss_types.h" |
| 23 #include "crypto/third_party/nss/chromium-nss.h" | 23 #include "crypto/third_party/nss/chromium-nss.h" |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 class ObCertOIDWrapper { | 27 class DomainBoundCertOIDWrapper { |
| 28 public: | 28 public: |
| 29 static ObCertOIDWrapper* GetInstance() { | 29 static DomainBoundCertOIDWrapper* GetInstance() { |
| 30 // Instantiated as a leaky singleton to allow the singleton to be | 30 // Instantiated as a leaky singleton to allow the singleton to be |
| 31 // constructed on a worker thead that is not joined when a process | 31 // constructed on a worker thead that is not joined when a process |
| 32 // shuts down. | 32 // shuts down. |
| 33 return Singleton<ObCertOIDWrapper, | 33 return Singleton<DomainBoundCertOIDWrapper, |
| 34 LeakySingletonTraits<ObCertOIDWrapper> >::get(); | 34 LeakySingletonTraits<DomainBoundCertOIDWrapper> >::get(); |
| 35 } | 35 } |
| 36 | 36 |
| 37 SECOidTag ob_cert_oid_tag() const { | 37 SECOidTag domain_bound_cert_oid_tag() const { |
| 38 return ob_cert_oid_tag_; | 38 return domain_bound_cert_oid_tag_; |
| 39 } | 39 } |
| 40 | 40 |
| 41 private: | 41 private: |
| 42 friend struct DefaultSingletonTraits<ObCertOIDWrapper>; | 42 friend struct DefaultSingletonTraits<DomainBoundCertOIDWrapper>; |
| 43 | 43 |
| 44 ObCertOIDWrapper(); | 44 DomainBoundCertOIDWrapper(); |
| 45 | 45 |
| 46 SECOidTag ob_cert_oid_tag_; | 46 SECOidTag domain_bound_cert_oid_tag_; |
| 47 | 47 |
| 48 DISALLOW_COPY_AND_ASSIGN(ObCertOIDWrapper); | 48 DISALLOW_COPY_AND_ASSIGN(DomainBoundCertOIDWrapper); |
| 49 }; | 49 }; |
| 50 | 50 |
| 51 ObCertOIDWrapper::ObCertOIDWrapper(): ob_cert_oid_tag_(SEC_OID_UNKNOWN) { | 51 DomainBoundCertOIDWrapper::DomainBoundCertOIDWrapper() |
| 52 : domain_bound_cert_oid_tag_(SEC_OID_UNKNOWN) { |
| 52 // 1.3.6.1.4.1.11129.2.1.6 | 53 // 1.3.6.1.4.1.11129.2.1.6 |
| 53 // (iso.org.dod.internet.private.enterprises.google.googleSecurity. | 54 // (iso.org.dod.internet.private.enterprises.google.googleSecurity. |
| 54 // certificateExtensions.originBoundCertificate) | 55 // certificateExtensions.originBoundCertificate) |
| 55 static const uint8 kObCertOID[] = { | 56 static const uint8 kObCertOID[] = { |
| 56 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x06 | 57 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x06 |
| 57 }; | 58 }; |
| 58 SECOidData oid_data; | 59 SECOidData oid_data; |
| 59 memset(&oid_data, 0, sizeof(oid_data)); | 60 memset(&oid_data, 0, sizeof(oid_data)); |
| 60 oid_data.oid.data = const_cast<uint8*>(kObCertOID); | 61 oid_data.oid.data = const_cast<uint8*>(kObCertOID); |
| 61 oid_data.oid.len = sizeof(kObCertOID); | 62 oid_data.oid.len = sizeof(kObCertOID); |
| 62 oid_data.offset = SEC_OID_UNKNOWN; | 63 oid_data.offset = SEC_OID_UNKNOWN; |
| 63 oid_data.desc = "Origin Bound Certificate"; | 64 oid_data.desc = "Origin Bound Certificate"; |
| 64 oid_data.mechanism = CKM_INVALID_MECHANISM; | 65 oid_data.mechanism = CKM_INVALID_MECHANISM; |
| 65 oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION; | 66 oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION; |
| 66 ob_cert_oid_tag_ = SECOID_AddEntry(&oid_data); | 67 domain_bound_cert_oid_tag_ = SECOID_AddEntry(&oid_data); |
| 67 if (ob_cert_oid_tag_ == SEC_OID_UNKNOWN) | 68 if (domain_bound_cert_oid_tag_ == SEC_OID_UNKNOWN) |
| 68 LOG(ERROR) << "OB_CERT OID tag creation failed"; | 69 LOG(ERROR) << "OB_CERT OID tag creation failed"; |
| 69 } | 70 } |
| 70 | 71 |
| 71 // Creates a Certificate object that may be passed to the SignCertificate | 72 // Creates a Certificate object that may be passed to the SignCertificate |
| 72 // method to generate an X509 certificate. | 73 // method to generate an X509 certificate. |
| 73 // Returns NULL if an error is encountered in the certificate creation | 74 // Returns NULL if an error is encountered in the certificate creation |
| 74 // process. | 75 // process. |
| 75 // Caller responsible for freeing returned certificate object. | 76 // Caller responsible for freeing returned certificate object. |
| 76 CERTCertificate* CreateCertificate( | 77 CERTCertificate* CreateCertificate( |
| 77 SECKEYPublicKey* public_key, | 78 SECKEYPublicKey* public_key, |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 DLOG(ERROR) << "DerSignData: " << PORT_GetError(); | 163 DLOG(ERROR) << "DerSignData: " << PORT_GetError(); |
| 163 return false; | 164 return false; |
| 164 } | 165 } |
| 165 | 166 |
| 166 // Save the signed result to the cert. | 167 // Save the signed result to the cert. |
| 167 cert->derCert = *result; | 168 cert->derCert = *result; |
| 168 | 169 |
| 169 return true; | 170 return true; |
| 170 } | 171 } |
| 171 | 172 |
| 172 bool CreateOriginBoundCertInternal( | 173 bool CreateDomainBoundCertInternal( |
| 173 SECKEYPublicKey* public_key, | 174 SECKEYPublicKey* public_key, |
| 174 SECKEYPrivateKey* private_key, | 175 SECKEYPrivateKey* private_key, |
| 175 const std::string& origin, | 176 const std::string& domain, |
| 176 uint32 serial_number, | 177 uint32 serial_number, |
| 177 base::Time not_valid_before, | 178 base::Time not_valid_before, |
| 178 base::Time not_valid_after, | 179 base::Time not_valid_after, |
| 179 std::string* der_cert) { | 180 std::string* der_cert) { |
| 180 | 181 |
| 181 CERTCertificate* cert = CreateCertificate(public_key, | 182 CERTCertificate* cert = CreateCertificate(public_key, |
| 182 "CN=anonymous.invalid", | 183 "CN=anonymous.invalid", |
| 183 serial_number, | 184 serial_number, |
| 184 not_valid_before, | 185 not_valid_before, |
| 185 not_valid_after); | 186 not_valid_after); |
| 186 | 187 |
| 187 if (!cert) | 188 if (!cert) |
| 188 return false; | 189 return false; |
| 189 | 190 |
| 190 // Create opaque handle used to add extensions later. | 191 // Create opaque handle used to add extensions later. |
| 191 void* cert_handle; | 192 void* cert_handle; |
| 192 if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { | 193 if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { |
| 193 LOG(ERROR) << "Unable to get opaque handle for adding extensions"; | 194 LOG(ERROR) << "Unable to get opaque handle for adding extensions"; |
| 194 CERT_DestroyCertificate(cert); | 195 CERT_DestroyCertificate(cert); |
| 195 return false; | 196 return false; |
| 196 } | 197 } |
| 197 | 198 |
| 198 // Create SECItem for IA5String encoding. | 199 // Create SECItem for IA5String encoding. |
| 199 SECItem origin_string_item = { | 200 SECItem domain_string_item = { |
| 200 siAsciiString, | 201 siAsciiString, |
| 201 (unsigned char*)origin.data(), | 202 (unsigned char*)domain.data(), |
| 202 origin.size() | 203 domain.size() |
| 203 }; | 204 }; |
| 204 | 205 |
| 205 // IA5Encode and arena allocate SECItem | 206 // IA5Encode and arena allocate SECItem |
| 206 SECItem* asn1_origin_string = SEC_ASN1EncodeItem( | 207 SECItem* asn1_domain_string = SEC_ASN1EncodeItem( |
| 207 cert->arena, NULL, &origin_string_item, | 208 cert->arena, NULL, &domain_string_item, |
| 208 SEC_ASN1_GET(SEC_IA5StringTemplate)); | 209 SEC_ASN1_GET(SEC_IA5StringTemplate)); |
| 209 if (asn1_origin_string == NULL) { | 210 if (asn1_domain_string == NULL) { |
| 210 LOG(ERROR) << "Unable to get ASN1 encoding for origin in ob_cert extension"; | 211 LOG(ERROR) << "Unable to get ASN1 encoding for domain in domain_bound_cert" |
| 212 " extension"; |
| 211 CERT_DestroyCertificate(cert); | 213 CERT_DestroyCertificate(cert); |
| 212 return false; | 214 return false; |
| 213 } | 215 } |
| 214 | 216 |
| 215 // Add the extension to the opaque handle | 217 // Add the extension to the opaque handle |
| 216 if (CERT_AddExtension(cert_handle, | 218 if (CERT_AddExtension( |
| 217 ObCertOIDWrapper::GetInstance()->ob_cert_oid_tag(), | 219 cert_handle, |
| 218 asn1_origin_string, | 220 DomainBoundCertOIDWrapper::GetInstance()->domain_bound_cert_oid_tag(), |
| 219 PR_TRUE, PR_TRUE) != SECSuccess){ | 221 asn1_domain_string, PR_TRUE, PR_TRUE) != SECSuccess){ |
| 220 LOG(ERROR) << "Unable to add origin bound cert extension to opaque handle"; | 222 LOG(ERROR) << "Unable to add domain bound cert extension to opaque handle"; |
| 221 CERT_DestroyCertificate(cert); | 223 CERT_DestroyCertificate(cert); |
| 222 return false; | 224 return false; |
| 223 } | 225 } |
| 224 | 226 |
| 225 // Copy extension into x509 cert | 227 // Copy extension into x509 cert |
| 226 if (CERT_FinishExtensions(cert_handle) != SECSuccess){ | 228 if (CERT_FinishExtensions(cert_handle) != SECSuccess){ |
| 227 LOG(ERROR) << "Unable to copy extension to X509 cert"; | 229 LOG(ERROR) << "Unable to copy extension to X509 cert"; |
| 228 CERT_DestroyCertificate(cert); | 230 CERT_DestroyCertificate(cert); |
| 229 return false; | 231 return false; |
| 230 } | 232 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 return NULL; | 267 return NULL; |
| 266 | 268 |
| 267 if (!SignCertificate(cert, private_key)) { | 269 if (!SignCertificate(cert, private_key)) { |
| 268 CERT_DestroyCertificate(cert); | 270 CERT_DestroyCertificate(cert); |
| 269 return NULL; | 271 return NULL; |
| 270 } | 272 } |
| 271 | 273 |
| 272 return cert; | 274 return cert; |
| 273 } | 275 } |
| 274 | 276 |
| 275 bool CreateOriginBoundCertEC( | 277 bool CreateDomainBoundCertEC( |
| 276 crypto::ECPrivateKey* key, | 278 crypto::ECPrivateKey* key, |
| 277 const std::string& origin, | 279 const std::string& domain, |
| 278 uint32 serial_number, | 280 uint32 serial_number, |
| 279 base::Time not_valid_before, | 281 base::Time not_valid_before, |
| 280 base::Time not_valid_after, | 282 base::Time not_valid_after, |
| 281 std::string* der_cert) { | 283 std::string* der_cert) { |
| 282 DCHECK(key); | 284 DCHECK(key); |
| 283 return CreateOriginBoundCertInternal(key->public_key(), | 285 return CreateDomainBoundCertInternal(key->public_key(), |
| 284 key->key(), | 286 key->key(), |
| 285 origin, | 287 domain, |
| 286 serial_number, | 288 serial_number, |
| 287 not_valid_before, | 289 not_valid_before, |
| 288 not_valid_after, | 290 not_valid_after, |
| 289 der_cert); | 291 der_cert); |
| 290 } | 292 } |
| 291 | 293 |
| 292 } // namespace x509_util | 294 } // namespace x509_util |
| 293 | 295 |
| 294 } // namespace net | 296 } // namespace net |
| OLD | NEW |