| 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" | |
| 20 #include "crypto/nss_util.h" | 19 #include "crypto/nss_util.h" |
| 21 #include "crypto/nss_util_internal.h" | 20 #include "crypto/nss_util_internal.h" |
| 22 #include "crypto/rsa_private_key.h" | 21 #include "crypto/rsa_private_key.h" |
| 23 #include "crypto/scoped_nss_types.h" | 22 #include "crypto/scoped_nss_types.h" |
| 24 #include "crypto/third_party/nss/chromium-nss.h" | |
| 25 | 23 |
| 26 namespace { | 24 namespace { |
| 27 | 25 |
| 28 class ObCertOIDWrapper { | 26 class ObCertOIDWrapper { |
| 29 public: | 27 public: |
| 30 static ObCertOIDWrapper* GetInstance() { | 28 static ObCertOIDWrapper* GetInstance() { |
| 31 // Instantiated as a leaky singleton to allow the singleton to be | 29 // Instantiated as a leaky singleton to allow the singleton to be |
| 32 // constructed on a worker thead that is not joined when a process | 30 // constructed on a worker thead that is not joined when a process |
| 33 // shuts down. | 31 // shuts down. |
| 34 return Singleton<ObCertOIDWrapper, | 32 return Singleton<ObCertOIDWrapper, |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); | 150 arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate)); |
| 153 if (!encode_result) | 151 if (!encode_result) |
| 154 return false; | 152 return false; |
| 155 | 153 |
| 156 // Allocate space to contain the signed cert. | 154 // Allocate space to contain the signed cert. |
| 157 SECItem* result = SECITEM_AllocItem(arena, NULL, 0); | 155 SECItem* result = SECITEM_AllocItem(arena, NULL, 0); |
| 158 if (!result) | 156 if (!result) |
| 159 return false; | 157 return false; |
| 160 | 158 |
| 161 // Sign the ASN1 encoded cert and save it to |result|. | 159 // Sign the ASN1 encoded cert and save it to |result|. |
| 162 rv = DerSignData(arena, result, &der, key, algo_id); | 160 rv = SEC_DerSignData(arena, result, der.data, der.len, key, algo_id); |
| 163 if (rv != SECSuccess) { | 161 if (rv != SECSuccess) |
| 164 DLOG(ERROR) << "DerSignData: " << PORT_GetError(); | |
| 165 return false; | 162 return false; |
| 166 } | |
| 167 | 163 |
| 168 // Save the signed result to the cert. | 164 // Save the signed result to the cert. |
| 169 cert->derCert = *result; | 165 cert->derCert = *result; |
| 170 | 166 |
| 171 return true; | 167 return true; |
| 172 } | 168 } |
| 173 | 169 |
| 174 bool CreateOriginBoundCertInternal( | |
| 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 | |
| 246 } // namespace | 170 } // namespace |
| 247 | 171 |
| 248 namespace net { | 172 namespace net { |
| 249 | 173 |
| 250 namespace x509_util { | 174 namespace x509_util { |
| 251 | 175 |
| 252 CERTCertificate* CreateSelfSignedCert( | 176 CERTCertificate* CreateSelfSignedCert( |
| 253 SECKEYPublicKey* public_key, | 177 SECKEYPublicKey* public_key, |
| 254 SECKEYPrivateKey* private_key, | 178 SECKEYPrivateKey* private_key, |
| 255 const std::string& subject, | 179 const std::string& subject, |
| 256 uint32 serial_number, | 180 uint32 serial_number, |
| 257 base::TimeDelta valid_duration) { | 181 base::TimeDelta valid_duration) { |
| 258 CERTCertificate* cert = CreateCertificate(public_key, | 182 CERTCertificate* cert = CreateCertificate(public_key, |
| 259 subject, | 183 subject, |
| 260 serial_number, | 184 serial_number, |
| 261 valid_duration); | 185 valid_duration); |
| 262 if (!cert) | 186 if (!cert) |
| 263 return NULL; | 187 return NULL; |
| 264 | 188 |
| 265 if (!SignCertificate(cert, private_key)) { | 189 if (!SignCertificate(cert, private_key)) { |
| 266 CERT_DestroyCertificate(cert); | 190 CERT_DestroyCertificate(cert); |
| 267 return NULL; | 191 return NULL; |
| 268 } | 192 } |
| 269 | 193 |
| 270 return cert; | 194 return cert; |
| 271 } | 195 } |
| 272 | 196 |
| 273 bool CreateOriginBoundCertRSA( | 197 bool CreateOriginBoundCert( |
| 274 crypto::RSAPrivateKey* key, | 198 crypto::RSAPrivateKey* key, |
| 275 const std::string& origin, | 199 const std::string& origin, |
| 276 uint32 serial_number, | 200 uint32 serial_number, |
| 277 base::TimeDelta valid_duration, | 201 base::TimeDelta valid_duration, |
| 278 std::string* der_cert) { | 202 std::string* der_cert) { |
| 279 DCHECK(key); | 203 DCHECK(key); |
| 280 | 204 |
| 281 SECKEYPublicKey* public_key; | 205 SECKEYPublicKey* public_key; |
| 282 SECKEYPrivateKey* private_key; | 206 SECKEYPrivateKey* private_key; |
| 283 #if defined(USE_NSS) | 207 #if defined(USE_NSS) |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 | 242 |
| 319 public_key = SECKEY_ConvertToPublicKey(private_key); | 243 public_key = SECKEY_ConvertToPublicKey(private_key); |
| 320 if (!public_key) { | 244 if (!public_key) { |
| 321 NOTREACHED(); | 245 NOTREACHED(); |
| 322 return NULL; | 246 return NULL; |
| 323 } | 247 } |
| 324 scoped_public_key.reset(public_key); | 248 scoped_public_key.reset(public_key); |
| 325 } | 249 } |
| 326 #endif | 250 #endif |
| 327 | 251 |
| 328 return CreateOriginBoundCertInternal(public_key, | 252 CERTCertificate* cert = CreateCertificate(public_key, |
| 329 private_key, | 253 "CN=anonymous.invalid", |
| 330 origin, | 254 serial_number, |
| 331 serial_number, | 255 valid_duration); |
| 332 valid_duration, | |
| 333 der_cert); | |
| 334 } | |
| 335 | 256 |
| 336 bool CreateOriginBoundCertEC( | 257 if (!cert) |
| 337 crypto::ECPrivateKey* key, | 258 return false; |
| 338 const std::string& origin, | 259 |
| 339 uint32 serial_number, | 260 // Create opaque handle used to add extensions later. |
| 340 base::TimeDelta valid_duration, | 261 void* cert_handle; |
| 341 std::string* der_cert) { | 262 if ((cert_handle = CERT_StartCertExtensions(cert)) == NULL) { |
| 342 DCHECK(key); | 263 LOG(ERROR) << "Unable to get opaque handle for adding extensions"; |
| 343 return CreateOriginBoundCertInternal(key->public_key(), | 264 CERT_DestroyCertificate(cert); |
| 344 key->key(), | 265 return false; |
| 345 origin, | 266 } |
| 346 serial_number, | 267 |
| 347 valid_duration, | 268 // Create SECItem for IA5String encoding. |
| 348 der_cert); | 269 SECItem origin_string_item = { |
| 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; |
| 349 } | 314 } |
| 350 | 315 |
| 351 } // namespace x509_util | 316 } // namespace x509_util |
| 352 | 317 |
| 353 } // namespace net | 318 } // namespace net |
| OLD | NEW |