1/* 2 * crypto-embedded.c 3 * libsecurity_smime 4 * 5 * Created by Conrad Sauerwald on 2/7/08. 6 * Copyright (c) 2008-2011,2013 Apple Inc. All Rights Reserved. 7 * 8 */ 9 10#include <stdio.h> 11 12#include "cert.h" 13#include "cryptohi.h" 14 15#include "cmstpriv.h" 16#include "secoid.h" 17#include "cmspriv.h" 18 19#include <libDER/DER_Decode.h> 20#include <security_asn1/secerr.h> 21#include <security_asn1/secport.h> 22 23#include <Security/SecBase.h> 24 25#include <CoreFoundation/CFNumber.h> 26#include <CoreFoundation/CFString.h> 27 28#include <Security/oidsalg.h> 29#include <Security/SecPolicy.h> 30#include <Security/SecItem.h> 31#include <Security/SecIdentity.h> 32#include <Security/SecCertificateInternal.h> 33#include <Security/SecKeyPriv.h> 34 35#include <CommonCrypto/CommonDigest.h> 36#include <AssertMacros.h> 37 38SECStatus 39CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs, 40 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef) 41{ 42 SecTrustRef trust = NULL; 43 OSStatus rv; 44 45 rv = SecTrustCreateWithCertificates(certs, policies, &trust); 46 if (rv) 47 goto loser; 48 49 CFDateRef verifyDate = CFDateCreate(NULL, stime); 50 rv = SecTrustSetVerifyDate(trust, verifyDate); 51 CFRelease(verifyDate); 52 if (rv) 53 goto loser; 54 55 if (trustRef) 56 { 57 *trustRef = trust; 58 } 59 else 60 { 61 SecTrustResultType result; 62 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */ 63 rv = SecTrustEvaluate(trust, &result); 64 if (rv) 65 goto loser; 66 67 switch (result) 68 { 69 case kSecTrustResultProceed: 70 case kSecTrustResultUnspecified: 71 /* TP Verification succeeded and there was either a UserTurst entry 72 telling us to procceed, or no user trust setting was specified. */ 73 CFRelease(trust); 74 break; 75 default: 76 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); 77 rv = SECFailure; 78 goto loser; 79 break; 80 } 81 } 82 83 return SECSuccess; 84loser: 85 if (trust) 86 CFRelease(trust); 87 88 return rv; 89} 90 91 92SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray, 93 char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win) 94{ 95 CFStringRef nickname_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, nickname, kCFStringEncodingUTF8); 96 const void *keys[] = { kSecClass, kSecAttrLabel }; 97 const void *values[] = { kSecClassCertificate, nickname_cfstr }; 98 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); 99 CFTypeRef result = NULL; 100 SecItemCopyMatching(query, &result); 101 CFRelease(query); 102 CFRelease(nickname_cfstr); 103 return (SecCertificateRef)result; 104} 105 106CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot) 107{ 108 CFMutableArrayRef certs = NULL; 109 SecPolicyRef policy = NULL; 110 SecTrustRef trust = NULL; 111 CFArrayRef wrappedCert = NULL; 112 113 policy = SecPolicyCreateBasicX509(); 114 if (!policy) 115 goto out; 116 117 wrappedCert = CERT_CertListFromCert(cert); 118 if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust)) 119 goto out; 120 121 SecTrustResultType result; 122 if (SecTrustEvaluate(trust, &result)) 123 goto out; 124 CFIndex idx, count = SecTrustGetCertificateCount(trust); 125 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); 126 for(idx = 0; idx < count; idx++) 127 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx)); 128 129out: 130 if (trust) CFRelease(trust); 131 if (policy) CFRelease(policy); 132 if (wrappedCert) CFRelease(wrappedCert); 133 134 return certs; 135} 136 137CFArrayRef CERT_CertListFromCert(SecCertificateRef cert) 138{ 139 const void *value = cert; 140 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL; 141} 142 143CFArrayRef CERT_DupCertList(CFArrayRef oldList) 144{ 145 CFRetain(oldList); 146 return oldList; 147} 148 149// Extract a public key object from a SubjectPublicKeyInfo 150SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert) 151{ 152 return SecCertificateCopyPublicKey(cert); 153} 154 155// Extract the issuer and serial number from a certificate 156SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert) 157{ 158 SecCmsIssuerAndSN *certIssuerAndSN; 159 160 void *mark; 161 mark = PORT_ArenaMark(pl); 162 CFDataRef serial_data = NULL; 163 CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert); 164 if (!issuer_data) 165 goto loser; 166 serial_data = SecCertificateCopySerialNumber(cert); 167 if (!serial_data) 168 goto loser; 169 170 SecAsn1Item serialNumber = { CFDataGetLength(serial_data), 171 (uint8_t *)CFDataGetBytePtr(serial_data) }; 172 SecAsn1Item issuer = { CFDataGetLength(issuer_data), 173 (uint8_t *)CFDataGetBytePtr(issuer_data) }; 174 175 /* Allocate the SecCmsIssuerAndSN struct. */ 176 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN)); 177 if (certIssuerAndSN == NULL) 178 goto loser; 179 180 /* Copy the issuer. */ 181 certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length); 182 if (!certIssuerAndSN->derIssuer.Data) 183 goto loser; 184 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length); 185 certIssuerAndSN->derIssuer.Length = issuer.Length; 186 187 /* Copy the serialNumber. */ 188 certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length); 189 if (!certIssuerAndSN->serialNumber.Data) 190 goto loser; 191 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length); 192 certIssuerAndSN->serialNumber.Length = serialNumber.Length; 193 194 CFRelease(serial_data); 195 CFRelease(issuer_data); 196 197 PORT_ArenaUnmark(pl, mark); 198 199 return certIssuerAndSN; 200 201loser: 202 if (serial_data) 203 CFRelease(serial_data); 204 if (issuer_data) 205 CFRelease(issuer_data); 206 PORT_ArenaRelease(pl, mark); 207 PORT_SetError(SEC_INTERNAL_ONLY); 208 209 return NULL; 210} 211 212// find the smime symmetric capabilities profile for a given cert 213SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert) 214{ 215 return NULL; 216} 217 218// Generate a certificate key from the issuer and serialnumber, then look it up in the database. 219// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for 220static CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef class, const SecCmsIssuerAndSN *issuerAndSN) 221{ 222 CFTypeRef ident = NULL; 223 CFDictionaryRef query = NULL; 224 CFDataRef issuer = NULL; 225 CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, 226 issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length, 227 kCFAllocatorNull); 228 229 DERItem der_issuer = { issuerAndSN->derIssuer.Data, 230 issuerAndSN->derIssuer.Length }; 231 DERDecodedInfo content; 232 require_noerr_quiet(DERDecodeItem(&der_issuer, &content), out); 233 require_quiet(issuer = createNormalizedX501Name(kCFAllocatorDefault, 234 &content.content), out); 235 236 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate)) 237 { 238 CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray); 239 for (c = 0; c < count; c++) { 240 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c); 241 if (CFEqual(SecCertificateGetNormalizedIssuerContent(cert), issuer)) { 242 CFDataRef cert_serial = SecCertificateCopySerialNumber(cert); 243 bool found = CFEqual(cert_serial, serial); 244 CFRelease(cert_serial); 245 if (found) { 246 CFRetain(cert); 247 ident = cert; 248 goto out; 249 } 250 } 251 } 252 } 253 254 const void *keys[] = { kSecClass, kSecAttrIssuer, kSecAttrSerialNumber, kSecReturnRef }; 255 const void *values[] = { class, issuer, serial, kCFBooleanTrue }; 256 query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); 257 require_noerr_quiet(SecItemCopyMatching(query, (CFTypeRef*)&ident), out); 258 259out: 260 if (query) 261 CFRelease(query); 262 if (issuer) 263 CFRelease(issuer); 264 if (serial) 265 CFRelease(serial); 266 267 return ident; 268} 269 270SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN) 271{ 272 return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN); 273} 274 275SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN) 276{ 277 return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN); 278} 279 280SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused, const SecAsn1Item *subjKeyID) 281{ 282 SecIdentityRef ident = NULL; 283 CFDictionaryRef query = NULL; 284 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull); 285 286 const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef }; 287 const void *values[] = { kSecClassIdentity, subjectkeyid, kCFBooleanTrue }; 288 query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); 289 require_noerr_quiet(SecItemCopyMatching(query, (CFTypeRef*)&ident), out); 290 291out: 292 if (query) 293 CFRelease(query); 294 if (subjectkeyid) 295 CFRelease(subjectkeyid); 296 297 return ident; 298} 299 300 301 302SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey) 303{ 304 CFRetain(pubKey); 305 return pubKey; 306} 307 308void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey) 309{ 310 CFRelease(pubKey); 311} 312 313SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey) 314{ 315 CFRetain(privKey); 316 return privKey; 317} 318 319void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey) 320{ 321 CFRelease(privKey); 322} 323 324void CERT_DestroyCertificate(SecCertificateRef cert) 325{ 326 CFRelease(cert); 327} 328 329SecCertificateRef CERT_DupCertificate(SecCertificateRef cert) 330{ 331 CFRetain(cert); 332 return cert; 333} 334 335SECStatus 336WRAP_PubWrapSymKey(SecPublicKeyRef publickey, 337 SecSymmetricKeyRef bulkkey, 338 SecAsn1Item * encKey) 339{ 340 return SecKeyEncrypt(publickey, kSecPaddingPKCS1, 341 CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey), 342 encKey->Data, &encKey->Length); 343} 344 345SecSymmetricKeyRef 346WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag) 347{ 348 size_t bulkkey_size = encKey->Length; 349 uint8_t bulkkey_buffer[bulkkey_size]; 350 if (SecKeyDecrypt(privkey, kSecPaddingPKCS1, 351 encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size)) 352 return NULL; 353 354 CFDataRef bulkkey = CFDataCreate(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size); 355 return (SecSymmetricKeyRef)bulkkey; 356} 357 358 359bool 360CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial) 361{ 362 do { 363 CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert); 364 if (!cert_issuer) 365 break; 366 if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) || 367 memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) { 368 CFRelease(cert_issuer); 369 break; 370 } 371 CFRelease(cert_issuer); 372 CFDataRef cert_serial = SecCertificateCopySerialNumber(cert); 373 if (!cert_serial) 374 break; 375 if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) || 376 memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) { 377 CFRelease(cert_serial); 378 break; 379 } 380 CFRelease(cert_serial); 381 return true; 382 } while(0); 383 return false; 384} 385