Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/nss_util.h" | 20 #include "crypto/nss_util.h" |
| 20 #include "crypto/nss_util_internal.h" | 21 #include "crypto/nss_util_internal.h" |
| 21 #include "crypto/rsa_private_key.h" | 22 #include "crypto/rsa_private_key.h" |
| 22 #include "crypto/scoped_nss_types.h" | 23 #include "crypto/scoped_nss_types.h" |
| 24 #include "crypto/third_party/nss/chromium-nss.h" | |
| 23 | 25 |
| 24 namespace { | 26 namespace { |
| 25 | 27 |
| 26 class ObCertOIDWrapper { | 28 class ObCertOIDWrapper { |
| 27 public: | 29 public: |
| 28 static ObCertOIDWrapper* GetInstance() { | 30 static ObCertOIDWrapper* GetInstance() { |
| 29 // Instantiated as a leaky singleton to allow the singleton to be | 31 // Instantiated as a leaky singleton to allow the singleton to be |
| 30 // constructed on a worker thead that is not joined when a process | 32 // constructed on a worker thead that is not joined when a process |
| 31 // shuts down. | 33 // shuts down. |
| 32 return Singleton<ObCertOIDWrapper, | 34 return Singleton<ObCertOIDWrapper, |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); | 152 arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); |
| 151 if (!encode_result) | 153 if (!encode_result) |
| 152 return false; | 154 return false; |
| 153 | 155 |
| 154 // Allocate space to contain the signed cert. | 156 // Allocate space to contain the signed cert. |
| 155 SECItem* result = SECITEM_AllocItem(arena, NULL, 0); | 157 SECItem* result = SECITEM_AllocItem(arena, NULL, 0); |
| 156 if (!result) | 158 if (!result) |
| 157 return false; | 159 return false; |
| 158 | 160 |
| 159 // Sign the ASN1 encoded cert and save it to |result|. | 161 // Sign the ASN1 encoded cert and save it to |result|. |
| 160 rv = SEC_DerSignData(arena, result, der.data, der.len, key, algo_id); | 162 rv = DerSignData(arena, result, &der, key, algo_id); |
| 161 if (rv != SECSuccess) | 163 if (rv != SECSuccess) { |
| 164 DLOG(ERROR) << "DerSignData: " << PORT_GetError(); | |
| 162 return false; | 165 return false; |
| 166 } | |
| 163 | 167 |
| 164 // Save the signed result to the cert. | 168 // Save the signed result to the cert. |
| 165 cert->derCert = *result; | 169 cert->derCert = *result; |
| 166 | 170 |
| 167 return true; | 171 return true; |
| 168 } | 172 } |
| 169 | 173 |
| 174 bool CreateOriginBoundCert( | |
|
wtc
2011/11/15 03:10:57
It may be better to name this function CreateOrigi
mattm
2011/11/15 05:42:31
Done.
| |
| 175 SECKEYPublicKey* public_key, | |
| 176 SECKEYPrivateKey* private_key, | |
| 177 const std::string& origin, | |
| 178 uint32 serial_number, | |
| 179 base::TimeDelta valid_duration, | |
| 180 std::string* der_cert) { | |
| 181 | |
| 182 CERTCertificate* cert = CreateCertificate(public_key, | |
| 183 "CN=anonymous.invalid", | |
| 184 serial_number, | |
| 185 valid_duration); | |
| 186 | |
| 187 if (!cert) | |
| 188 return false; | |
| 189 | |
| 190 // Create opaque handle used to add extensions later. | |
| 191 void* cert_handle; | |
| 192 if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { | |
| 193 LOG(ERROR) << "Unable to get opaque handle for adding extensions"; | |
| 194 CERT_DestroyCertificate(cert); | |
| 195 return false; | |
| 196 } | |
| 197 | |
| 198 // Create SECItem for IA5String encoding. | |
| 199 SECItem origin_string_item = { | |
| 200 siAsciiString, | |
| 201 (unsigned char*)origin.data(), | |
| 202 origin.size() | |
| 203 }; | |
| 204 | |
| 205 // IA5Encode and arena allocate SECItem | |
| 206 SECItem* asn1_origin_string = SEC_ASN1EncodeItem( | |
| 207 cert->arena, NULL, &origin_string_item, | |
| 208 SEC_ASN1_GET(SEC_IA5StringTemplate)); | |
| 209 if (asn1_origin_string == NULL) { | |
| 210 LOG(ERROR) << "Unable to get ASN1 encoding for origin in ob_cert extension"; | |
| 211 CERT_DestroyCertificate(cert); | |
| 212 return false; | |
| 213 } | |
| 214 | |
| 215 // Add the extension to the opaque handle | |
| 216 if (CERT_AddExtension(cert_handle, | |
| 217 ObCertOIDWrapper::GetInstance()->ob_cert_oid_tag(), | |
| 218 asn1_origin_string, | |
| 219 PR_TRUE, PR_TRUE) != SECSuccess){ | |
| 220 LOG(ERROR) << "Unable to add origin bound cert extension to opaque handle"; | |
| 221 CERT_DestroyCertificate(cert); | |
| 222 return false; | |
| 223 } | |
| 224 | |
| 225 // Copy extension into x509 cert | |
| 226 if (CERT_FinishExtensions(cert_handle) != SECSuccess){ | |
| 227 LOG(ERROR) << "Unable to copy extension to X509 cert"; | |
| 228 CERT_DestroyCertificate(cert); | |
| 229 return false; | |
| 230 } | |
| 231 | |
| 232 if (!SignCertificate(cert, private_key)) { | |
| 233 CERT_DestroyCertificate(cert); | |
| 234 return false; | |
| 235 } | |
| 236 | |
| 237 DCHECK(cert->derCert.len); | |
| 238 // XXX copied from X509Certificate::GetDEREncoded | |
| 239 der_cert->clear(); | |
| 240 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), | |
| 241 cert->derCert.len); | |
| 242 CERT_DestroyCertificate(cert); | |
| 243 return true; | |
| 244 } | |
| 245 | |
| 170 } // namespace | 246 } // namespace |
| 171 | 247 |
| 172 namespace net { | 248 namespace net { |
| 173 | 249 |
| 174 namespace x509_util { | 250 namespace x509_util { |
| 175 | 251 |
| 176 CERTCertificate* CreateSelfSignedCert( | 252 CERTCertificate* CreateSelfSignedCert( |
| 177 SECKEYPublicKey* public_key, | 253 SECKEYPublicKey* public_key, |
| 178 SECKEYPrivateKey* private_key, | 254 SECKEYPrivateKey* private_key, |
| 179 const std::string& subject, | 255 const std::string& subject, |
| 180 uint32 serial_number, | 256 uint32 serial_number, |
| 181 base::TimeDelta valid_duration) { | 257 base::TimeDelta valid_duration) { |
| 182 CERTCertificate* cert = CreateCertificate(public_key, | 258 CERTCertificate* cert = CreateCertificate(public_key, |
| 183 subject, | 259 subject, |
| 184 serial_number, | 260 serial_number, |
| 185 valid_duration); | 261 valid_duration); |
| 186 if (!cert) | 262 if (!cert) |
| 187 return NULL; | 263 return NULL; |
| 188 | 264 |
| 189 if (!SignCertificate(cert, private_key)) { | 265 if (!SignCertificate(cert, private_key)) { |
| 190 CERT_DestroyCertificate(cert); | 266 CERT_DestroyCertificate(cert); |
| 191 return NULL; | 267 return NULL; |
| 192 } | 268 } |
| 193 | 269 |
| 194 return cert; | 270 return cert; |
| 195 } | 271 } |
| 196 | 272 |
| 197 bool CreateOriginBoundCert( | 273 bool CreateOriginBoundCertRSA( |
| 198 crypto::RSAPrivateKey* key, | 274 crypto::RSAPrivateKey* key, |
| 199 const std::string& origin, | 275 const std::string& origin, |
| 200 uint32 serial_number, | 276 uint32 serial_number, |
| 201 base::TimeDelta valid_duration, | 277 base::TimeDelta valid_duration, |
| 202 std::string* der_cert) { | 278 std::string* der_cert) { |
| 203 DCHECK(key); | 279 DCHECK(key); |
| 204 | 280 |
| 205 SECKEYPublicKey* public_key; | 281 SECKEYPublicKey* public_key; |
| 206 SECKEYPrivateKey* private_key; | 282 SECKEYPrivateKey* private_key; |
| 207 #if defined(USE_NSS) | 283 #if defined(USE_NSS) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 | 318 |
| 243 public_key = SECKEY_ConvertToPublicKey(private_key); | 319 public_key = SECKEY_ConvertToPublicKey(private_key); |
| 244 if (!public_key) { | 320 if (!public_key) { |
| 245 NOTREACHED(); | 321 NOTREACHED(); |
| 246 return NULL; | 322 return NULL; |
| 247 } | 323 } |
| 248 scoped_public_key.reset(public_key); | 324 scoped_public_key.reset(public_key); |
| 249 } | 325 } |
| 250 #endif | 326 #endif |
| 251 | 327 |
| 252 CERTCertificate* cert = CreateCertificate(public_key, | 328 return CreateOriginBoundCert(public_key, |
| 253 "CN=anonymous.invalid", | 329 private_key, |
| 254 serial_number, | 330 origin, |
| 255 valid_duration); | 331 serial_number, |
| 332 valid_duration, | |
| 333 der_cert); | |
| 334 } | |
| 256 | 335 |
| 257 if (!cert) | 336 bool CreateOriginBoundCertEC( |
| 258 return false; | 337 crypto::ECPrivateKey* key, |
| 259 | 338 const std::string& origin, |
| 260 // Create opaque handle used to add extensions later. | 339 uint32 serial_number, |
| 261 void* cert_handle; | 340 base::TimeDelta valid_duration, |
| 262 if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { | 341 std::string* der_cert) { |
| 263 LOG(ERROR) << "Unable to get opaque handle for adding extensions"; | 342 DCHECK(key); |
| 264 CERT_DestroyCertificate(cert); | 343 return CreateOriginBoundCert(key->public_key(), |
| 265 return false; | 344 key->key(), |
| 266 } | 345 origin, |
| 267 | 346 serial_number, |
| 268 // Create SECItem for IA5String encoding. | 347 valid_duration, |
| 269 SECItem origin_string_item = { | 348 der_cert); |
| 270 siAsciiString, | |
| 271 (unsigned char*)origin.data(), | |
| 272 origin.size() | |
| 273 }; | |
| 274 | |
| 275 // IA5Encode and arena allocate SECItem | |
| 276 SECItem* asn1_origin_string = SEC_ASN1EncodeItem( | |
| 277 cert->arena, NULL, &origin_string_item, | |
| 278 SEC_ASN1_GET(SEC_IA5StringTemplate)); | |
| 279 if (asn1_origin_string == NULL) { | |
| 280 LOG(ERROR) << "Unable to get ASN1 encoding for origin in ob_cert extension"; | |
| 281 CERT_DestroyCertificate(cert); | |
| 282 return false; | |
| 283 } | |
| 284 | |
| 285 // Add the extension to the opaque handle | |
| 286 if (CERT_AddExtension(cert_handle, | |
| 287 ObCertOIDWrapper::GetInstance()->ob_cert_oid_tag(), | |
| 288 asn1_origin_string, | |
| 289 PR_TRUE, PR_TRUE) != SECSuccess){ | |
| 290 LOG(ERROR) << "Unable to add origin bound cert extension to opaque handle"; | |
| 291 CERT_DestroyCertificate(cert); | |
| 292 return false; | |
| 293 } | |
| 294 | |
| 295 // Copy extension into x509 cert | |
| 296 if (CERT_FinishExtensions(cert_handle) != SECSuccess){ | |
| 297 LOG(ERROR) << "Unable to copy extension to X509 cert"; | |
| 298 CERT_DestroyCertificate(cert); | |
| 299 return false; | |
| 300 } | |
| 301 | |
| 302 if (!SignCertificate(cert, private_key)) { | |
| 303 CERT_DestroyCertificate(cert); | |
| 304 return false; | |
| 305 } | |
| 306 | |
| 307 DCHECK(cert->derCert.len); | |
| 308 // XXX copied from X509Certificate::GetDEREncoded | |
| 309 der_cert->clear(); | |
| 310 der_cert->append(reinterpret_cast<char*>(cert->derCert.data), | |
| 311 cert->derCert.len); | |
| 312 CERT_DestroyCertificate(cert); | |
| 313 return true; | |
| 314 } | 349 } |
| 315 | 350 |
| 316 } // namespace x509_util | 351 } // namespace x509_util |
| 317 | 352 |
| 318 } // namespace net | 353 } // namespace net |
| OLD | NEW |