1 // Copyright 2014 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/ssl/openssl_platform_key.h" 6 7 #include <openssl/err.h> 8 #include <openssl/evp.h> 9 #include <openssl/rsa.h> 10 11 #include <Security/cssm.h> 12 #include <Security/SecBase.h> 13 #include <Security/SecCertificate.h> 14 #include <Security/SecIdentity.h> 15 #include <Security/SecKey.h> 16 17 #include "base/lazy_instance.h" 18 #include "base/location.h" 19 #include "base/logging.h" 20 #include "base/mac/mac_logging.h" 21 #include "base/mac/scoped_cftyperef.h" 22 #include "base/memory/scoped_policy.h" 23 #include "base/memory/scoped_ptr.h" 24 #include "base/synchronization/lock.h" 25 #include "crypto/mac_security_services_lock.h" 26 #include "net/base/net_errors.h" 27 #include "net/cert/x509_certificate.h" 28 #include "net/ssl/openssl_ssl_util.h" 29 30 namespace net { 31 32 namespace { 33 34 class ScopedCSSM_CC_HANDLE { 35 public: 36 ScopedCSSM_CC_HANDLE() : handle_(0) { 37 } 38 39 ~ScopedCSSM_CC_HANDLE() { 40 reset(); 41 } 42 43 CSSM_CC_HANDLE get() const { 44 return handle_; 45 } 46 47 void reset() { 48 if (handle_) 49 CSSM_DeleteContext(handle_); 50 handle_ = 0; 51 } 52 53 CSSM_CC_HANDLE* InitializeInto() { 54 reset(); 55 return &handle_; 56 } 57 private: 58 CSSM_CC_HANDLE handle_; 59 60 DISALLOW_COPY_AND_ASSIGN(ScopedCSSM_CC_HANDLE); 61 }; 62 63 // Looks up the private key for |certificate| in KeyChain and returns 64 // a SecKeyRef or NULL on failure. The caller takes ownership of the 65 // result. 66 SecKeyRef FetchSecKeyRefForCertificate(const X509Certificate* certificate) { 67 OSStatus status; 68 base::ScopedCFTypeRef<SecIdentityRef> identity; 69 { 70 base::AutoLock lock(crypto::GetMacSecurityServicesLock()); 71 status = SecIdentityCreateWithCertificate( 72 NULL, certificate->os_cert_handle(), identity.InitializeInto()); 73 } 74 if (status != noErr) { 75 OSSTATUS_LOG(WARNING, status); 76 return NULL; 77 } 78 79 base::ScopedCFTypeRef<SecKeyRef> private_key; 80 status = SecIdentityCopyPrivateKey(identity, private_key.InitializeInto()); 81 if (status != noErr) { 82 OSSTATUS_LOG(WARNING, status); 83 return NULL; 84 } 85 86 return private_key.release(); 87 } 88 89 extern const RSA_METHOD mac_rsa_method; 90 extern const ECDSA_METHOD mac_ecdsa_method; 91 92 // KeyExData contains the data that is contained in the EX_DATA of the 93 // RSA and ECDSA objects that are created to wrap Mac system keys. 94 struct KeyExData { 95 KeyExData(SecKeyRef key, const CSSM_KEY* cssm_key) 96 : key(key, base::scoped_policy::RETAIN), cssm_key(cssm_key) {} 97 98 base::ScopedCFTypeRef<SecKeyRef> key; 99 const CSSM_KEY* cssm_key; 100 }; 101 102 // ExDataDup is called when one of the RSA or EC_KEY objects is 103 // duplicated. This is not supported and should never happen. 104 int ExDataDup(CRYPTO_EX_DATA* to, 105 const CRYPTO_EX_DATA* from, 106 void** from_d, 107 int idx, 108 long argl, 109 void* argp) { 110 CHECK_EQ((void*)NULL, *from_d); 111 return 0; 112 } 113 114 // ExDataFree is called when one of the RSA or EC_KEY objects is freed. 115 void ExDataFree(void* parent, 116 void* ptr, 117 CRYPTO_EX_DATA* ex_data, 118 int idx, 119 long argl, void* argp) { 120 KeyExData* data = reinterpret_cast<KeyExData*>(ptr); 121 delete data; 122 } 123 124 // BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA 125 // by forwarding the requested operations to Apple's CSSM 126 // implementation. 127 class BoringSSLEngine { 128 public: 129 BoringSSLEngine() 130 : rsa_index_(RSA_get_ex_new_index(0 /* argl */, 131 NULL /* argp */, 132 NULL /* new_func */, 133 ExDataDup, 134 ExDataFree)), 135 ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */, 136 NULL /* argp */, 137 NULL /* new_func */, 138 ExDataDup, 139 ExDataFree)), 140 engine_(ENGINE_new()) { 141 ENGINE_set_RSA_method( 142 engine_, &mac_rsa_method, sizeof(mac_rsa_method)); 143 ENGINE_set_ECDSA_method( 144 engine_, &mac_ecdsa_method, sizeof(mac_ecdsa_method)); 145 } 146 147 int rsa_ex_index() const { return rsa_index_; } 148 int ec_key_ex_index() const { return ec_key_index_; } 149 150 const ENGINE* engine() const { return engine_; } 151 152 private: 153 const int rsa_index_; 154 const int ec_key_index_; 155 ENGINE* const engine_; 156 }; 157 158 base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine = 159 LAZY_INSTANCE_INITIALIZER; 160 161 // Helper function for making a signature. 162 163 // MakeCSSMSignature uses the key information in |ex_data| to sign the 164 // |in_len| bytes pointed by |in|. It writes up to |max_out| bytes 165 // into the buffer pointed to by |out|, setting |*out_len| to the 166 // number of bytes written. It returns 1 on success and 0 on failure. 167 int MakeCSSMSignature(const KeyExData* ex_data, 168 size_t* out_len, 169 uint8_t* out, 170 size_t max_out, 171 const uint8_t* in, 172 size_t in_len) { 173 CSSM_CSP_HANDLE csp_handle; 174 OSStatus status = SecKeyGetCSPHandle(ex_data->key.get(), &csp_handle); 175 if (status != noErr) { 176 OSSTATUS_LOG(WARNING, status); 177 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); 178 return 0; 179 } 180 181 const CSSM_ACCESS_CREDENTIALS* cssm_creds = NULL; 182 status = SecKeyGetCredentials(ex_data->key.get(), CSSM_ACL_AUTHORIZATION_SIGN, 183 kSecCredentialTypeDefault, &cssm_creds); 184 if (status != noErr) { 185 OSSTATUS_LOG(WARNING, status); 186 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); 187 return 0; 188 } 189 190 ScopedCSSM_CC_HANDLE cssm_signature; 191 if (CSSM_CSP_CreateSignatureContext( 192 csp_handle, ex_data->cssm_key->KeyHeader.AlgorithmId, cssm_creds, 193 ex_data->cssm_key, cssm_signature.InitializeInto()) != CSSM_OK) { 194 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); 195 return 0; 196 } 197 198 if (ex_data->cssm_key->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { 199 // Set RSA blinding. 200 CSSM_CONTEXT_ATTRIBUTE blinding_attr; 201 blinding_attr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; 202 blinding_attr.AttributeLength = sizeof(uint32); 203 blinding_attr.Attribute.Uint32 = 1; 204 if (CSSM_UpdateContextAttributes( 205 cssm_signature.get(), 1, &blinding_attr) != CSSM_OK) { 206 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); 207 return 0; 208 } 209 } 210 211 CSSM_DATA hash_data; 212 hash_data.Length = in_len; 213 hash_data.Data = const_cast<uint8*>(in); 214 215 CSSM_DATA signature_data; 216 signature_data.Length = max_out; 217 signature_data.Data = out; 218 219 if (CSSM_SignData(cssm_signature.get(), &hash_data, 1, 220 CSSM_ALGID_NONE, &signature_data) != CSSM_OK) { 221 OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); 222 return 0; 223 } 224 225 *out_len = signature_data.Length; 226 return 1; 227 } 228 229 // Custom RSA_METHOD that uses the platform APIs for signing. 230 231 const KeyExData* RsaGetExData(const RSA* rsa) { 232 return reinterpret_cast<const KeyExData*>( 233 RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index())); 234 } 235 236 size_t RsaMethodSize(const RSA *rsa) { 237 const KeyExData *ex_data = RsaGetExData(rsa); 238 return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8; 239 } 240 241 int RsaMethodEncrypt(RSA* rsa, 242 size_t* out_len, 243 uint8_t* out, 244 size_t max_out, 245 const uint8_t* in, 246 size_t in_len, 247 int padding) { 248 NOTIMPLEMENTED(); 249 OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE); 250 return 0; 251 } 252 253 int RsaMethodSignRaw(RSA* rsa, 254 size_t* out_len, 255 uint8_t* out, 256 size_t max_out, 257 const uint8_t* in, 258 size_t in_len, 259 int padding) { 260 // Only support PKCS#1 padding. 261 DCHECK_EQ(RSA_PKCS1_PADDING, padding); 262 if (padding != RSA_PKCS1_PADDING) { 263 OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE); 264 return 0; 265 } 266 267 const KeyExData *ex_data = RsaGetExData(rsa); 268 if (!ex_data) { 269 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); 270 return 0; 271 } 272 DCHECK_EQ(CSSM_ALGID_RSA, ex_data->cssm_key->KeyHeader.AlgorithmId); 273 274 return MakeCSSMSignature(ex_data, out_len, out, max_out, in, in_len); 275 } 276 277 int RsaMethodDecrypt(RSA* rsa, 278 size_t* out_len, 279 uint8_t* out, 280 size_t max_out, 281 const uint8_t* in, 282 size_t in_len, 283 int padding) { 284 NOTIMPLEMENTED(); 285 OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE); 286 return 0; 287 } 288 289 int RsaMethodVerifyRaw(RSA* rsa, 290 size_t* out_len, 291 uint8_t* out, 292 size_t max_out, 293 const uint8_t* in, 294 size_t in_len, 295 int padding) { 296 NOTIMPLEMENTED(); 297 OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE); 298 return 0; 299 } 300 301 const RSA_METHOD mac_rsa_method = { 302 { 303 0 /* references */, 304 1 /* is_static */ 305 } /* common */, 306 NULL /* app_data */, 307 308 NULL /* init */, 309 NULL /* finish */, 310 RsaMethodSize, 311 NULL /* sign */, 312 NULL /* verify */, 313 RsaMethodEncrypt, 314 RsaMethodSignRaw, 315 RsaMethodDecrypt, 316 RsaMethodVerifyRaw, 317 NULL /* private_transform */, 318 NULL /* mod_exp */, 319 NULL /* bn_mod_exp */, 320 RSA_FLAG_OPAQUE, 321 NULL /* keygen */, 322 }; 323 324 crypto::ScopedEVP_PKEY CreateRSAWrapper(SecKeyRef key, 325 const CSSM_KEY* cssm_key) { 326 crypto::ScopedRSA rsa( 327 RSA_new_method(global_boringssl_engine.Get().engine())); 328 if (!rsa) 329 return crypto::ScopedEVP_PKEY(); 330 331 RSA_set_ex_data( 332 rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), 333 new KeyExData(key, cssm_key)); 334 335 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); 336 if (!pkey) 337 return crypto::ScopedEVP_PKEY(); 338 339 if (!EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) 340 return crypto::ScopedEVP_PKEY(); 341 342 return pkey.Pass(); 343 } 344 345 // Custom ECDSA_METHOD that uses the platform APIs. 346 // Note that for now, only signing through ECDSA_sign() is really supported. 347 // all other method pointers are either stubs returning errors, or no-ops. 348 349 const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) { 350 return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data( 351 ec_key, global_boringssl_engine.Get().ec_key_ex_index())); 352 } 353 354 size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { 355 const KeyExData* ex_data = EcKeyGetExData(ec_key); 356 // LogicalKeySizeInBits is the size of an EC public key. But an 357 // ECDSA signature length depends on the size of the base point's 358 // order. For P-256, P-384, and P-521, these two sizes are the same. 359 return (ex_data->cssm_key->KeyHeader.LogicalKeySizeInBits + 7) / 8; 360 } 361 362 int EcdsaMethodSign(const uint8_t* digest, 363 size_t digest_len, 364 uint8_t* sig, 365 unsigned int* sig_len, 366 EC_KEY* ec_key) { 367 const KeyExData *ex_data = EcKeyGetExData(ec_key); 368 if (!ex_data) { 369 OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); 370 return 0; 371 } 372 DCHECK_EQ(CSSM_ALGID_ECDSA, ex_data->cssm_key->KeyHeader.AlgorithmId); 373 374 // TODO(davidben): Fix BoringSSL to make sig_len a size_t*. 375 size_t out_len; 376 int ret = MakeCSSMSignature( 377 ex_data, &out_len, sig, ECDSA_size(ec_key), digest, digest_len); 378 if (!ret) 379 return 0; 380 *sig_len = out_len; 381 return 1; 382 } 383 384 int EcdsaMethodVerify(const uint8_t* digest, 385 size_t digest_len, 386 const uint8_t* sig, 387 size_t sig_len, 388 EC_KEY* eckey) { 389 NOTIMPLEMENTED(); 390 OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED); 391 return 0; 392 } 393 394 const ECDSA_METHOD mac_ecdsa_method = { 395 { 396 0 /* references */, 397 1 /* is_static */ 398 } /* common */, 399 NULL /* app_data */, 400 401 NULL /* init */, 402 NULL /* finish */, 403 EcdsaMethodGroupOrderSize, 404 EcdsaMethodSign, 405 EcdsaMethodVerify, 406 ECDSA_FLAG_OPAQUE, 407 }; 408 409 crypto::ScopedEVP_PKEY CreateECDSAWrapper(SecKeyRef key, 410 const CSSM_KEY* cssm_key) { 411 crypto::ScopedEC_KEY ec_key( 412 EC_KEY_new_method(global_boringssl_engine.Get().engine())); 413 if (!ec_key) 414 return crypto::ScopedEVP_PKEY(); 415 416 EC_KEY_set_ex_data( 417 ec_key.get(), global_boringssl_engine.Get().ec_key_ex_index(), 418 new KeyExData(key, cssm_key)); 419 420 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); 421 if (!pkey) 422 return crypto::ScopedEVP_PKEY(); 423 424 if (!EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) 425 return crypto::ScopedEVP_PKEY(); 426 427 return pkey.Pass(); 428 } 429 430 crypto::ScopedEVP_PKEY CreatePkeyWrapper(SecKeyRef key) { 431 const CSSM_KEY* cssm_key; 432 OSStatus status = SecKeyGetCSSMKey(key, &cssm_key); 433 if (status != noErr) 434 return crypto::ScopedEVP_PKEY(); 435 436 switch (cssm_key->KeyHeader.AlgorithmId) { 437 case CSSM_ALGID_RSA: 438 return CreateRSAWrapper(key, cssm_key); 439 case CSSM_ALGID_ECDSA: 440 return CreateECDSAWrapper(key, cssm_key); 441 default: 442 // TODO(davidben): Filter out anything other than ECDSA and RSA 443 // elsewhere. We don't support other key types. 444 NOTREACHED(); 445 LOG(ERROR) << "Unknown key type"; 446 return crypto::ScopedEVP_PKEY(); 447 } 448 } 449 450 } // namespace 451 452 crypto::ScopedEVP_PKEY FetchClientCertPrivateKey( 453 const X509Certificate* certificate) { 454 // Look up the private key. 455 base::ScopedCFTypeRef<SecKeyRef> private_key( 456 FetchSecKeyRefForCertificate(certificate)); 457 if (!private_key) 458 return crypto::ScopedEVP_PKEY(); 459 460 // Create an EVP_PKEY wrapper. 461 return CreatePkeyWrapper(private_key.get()); 462 } 463 464 } // namespace net 465