X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_smime/lib/crypto-embedded.c?ds=inline diff --git a/libsecurity_smime/lib/crypto-embedded.c b/libsecurity_smime/lib/crypto-embedded.c new file mode 100644 index 00000000..c9dd8e70 --- /dev/null +++ b/libsecurity_smime/lib/crypto-embedded.c @@ -0,0 +1,384 @@ +/* + * crypto-embedded.c + * libsecurity_smime + * + * Created by Conrad Sauerwald on 2/7/08. + * Copyright (c) 2008-2011,2013 Apple Inc. All Rights Reserved. + * + */ + +#include + +#include "cert.h" +#include "cryptohi.h" + +#include "cmstpriv.h" +#include "secoid.h" +#include "cmspriv.h" + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +SECStatus +CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs, + CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef) +{ + SecTrustRef trust = NULL; + OSStatus rv; + + rv = SecTrustCreateWithCertificates(certs, policies, &trust); + if (rv) + goto loser; + + CFDateRef verifyDate = CFDateCreate(NULL, stime); + rv = SecTrustSetVerifyDate(trust, verifyDate); + CFRelease(verifyDate); + if (rv) + goto loser; + + if (trustRef) + { + *trustRef = trust; + } + else + { + SecTrustResultType result; + /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */ + rv = SecTrustEvaluate(trust, &result); + if (rv) + goto loser; + + switch (result) + { + case kSecTrustResultProceed: + case kSecTrustResultUnspecified: + /* TP Verification succeeded and there was either a UserTurst entry + telling us to procceed, or no user trust setting was specified. */ + CFRelease(trust); + break; + default: + PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); + rv = SECFailure; + goto loser; + break; + } + } + + return SECSuccess; +loser: + if (trust) + CFRelease(trust); + + return rv; +} + + +SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray, + char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win) +{ + CFStringRef nickname_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, nickname, kCFStringEncodingUTF8); + const void *keys[] = { kSecClass, kSecAttrLabel }; + const void *values[] = { kSecClassCertificate, nickname_cfstr }; + CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); + CFTypeRef result = NULL; + SecItemCopyMatching(query, &result); + CFRelease(query); + CFRelease(nickname_cfstr); + return (SecCertificateRef)result; +} + +CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot) +{ + CFMutableArrayRef certs = NULL; + SecPolicyRef policy = NULL; + SecTrustRef trust = NULL; + CFArrayRef wrappedCert = NULL; + + policy = SecPolicyCreateBasicX509(); + if (!policy) + goto out; + + wrappedCert = CERT_CertListFromCert(cert); + if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust)) + goto out; + + SecTrustResultType result; + if (SecTrustEvaluate(trust, &result)) + goto out; + CFIndex idx, count = SecTrustGetCertificateCount(trust); + certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); + for(idx = 0; idx < count; idx++) + CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx)); + +out: + if (trust) CFRelease(trust); + if (policy) CFRelease(policy); + if (wrappedCert) CFRelease(wrappedCert); + + return certs; +} + +CFArrayRef CERT_CertListFromCert(SecCertificateRef cert) +{ + const void *value = cert; + return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL; +} + +CFArrayRef CERT_DupCertList(CFArrayRef oldList) +{ + CFRetain(oldList); + return oldList; +} + +// Extract a public key object from a SubjectPublicKeyInfo +SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert) +{ + return SecCertificateCopyPublicKey(cert); +} + +// Extract the issuer and serial number from a certificate +SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert) +{ + SecCmsIssuerAndSN *certIssuerAndSN; + + void *mark; + mark = PORT_ArenaMark(pl); + CFDataRef serial_data = NULL; + CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert); + if (!issuer_data) + goto loser; + serial_data = SecCertificateCopySerialNumber(cert); + if (!serial_data) + goto loser; + + SecAsn1Item serialNumber = { CFDataGetLength(serial_data), + (uint8_t *)CFDataGetBytePtr(serial_data) }; + SecAsn1Item issuer = { CFDataGetLength(issuer_data), + (uint8_t *)CFDataGetBytePtr(issuer_data) }; + + /* Allocate the SecCmsIssuerAndSN struct. */ + certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN)); + if (certIssuerAndSN == NULL) + goto loser; + + /* Copy the issuer. */ + certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length); + if (!certIssuerAndSN->derIssuer.Data) + goto loser; + PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length); + certIssuerAndSN->derIssuer.Length = issuer.Length; + + /* Copy the serialNumber. */ + certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length); + if (!certIssuerAndSN->serialNumber.Data) + goto loser; + PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length); + certIssuerAndSN->serialNumber.Length = serialNumber.Length; + + CFRelease(serial_data); + CFRelease(issuer_data); + + PORT_ArenaUnmark(pl, mark); + + return certIssuerAndSN; + +loser: + if (serial_data) + CFRelease(serial_data); + if (issuer_data) + CFRelease(issuer_data); + PORT_ArenaRelease(pl, mark); + PORT_SetError(SEC_INTERNAL_ONLY); + + return NULL; +} + +// find the smime symmetric capabilities profile for a given cert +SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert) +{ + return NULL; +} + +// Generate a certificate key from the issuer and serialnumber, then look it up in the database. +// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for +static CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef class, const SecCmsIssuerAndSN *issuerAndSN) +{ + CFTypeRef ident = NULL; + CFDictionaryRef query = NULL; + CFDataRef issuer = NULL; + CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length, + kCFAllocatorNull); + + DERItem der_issuer = { issuerAndSN->derIssuer.Data, + issuerAndSN->derIssuer.Length }; + DERDecodedInfo content; + require_noerr_quiet(DERDecodeItem(&der_issuer, &content), out); + require_quiet(issuer = createNormalizedX501Name(kCFAllocatorDefault, + &content.content), out); + + if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate)) + { + CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray); + for (c = 0; c < count; c++) { + SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c); + if (CFEqual(SecCertificateGetNormalizedIssuerContent(cert), issuer)) { + CFDataRef cert_serial = SecCertificateCopySerialNumber(cert); + bool found = CFEqual(cert_serial, serial); + CFRelease(cert_serial); + if (found) { + CFRetain(cert); + ident = cert; + goto out; + } + } + } + } + + const void *keys[] = { kSecClass, kSecAttrIssuer, kSecAttrSerialNumber, kSecReturnRef }; + const void *values[] = { class, issuer, serial, kCFBooleanTrue }; + query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); + require_noerr_quiet(SecItemCopyMatching(query, (CFTypeRef*)&ident), out); + +out: + if (query) + CFRelease(query); + if (issuer) + CFRelease(issuer); + if (serial) + CFRelease(serial); + + return ident; +} + +SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN) +{ + return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN); +} + +SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN) +{ + return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN); +} + +SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused, const SecAsn1Item *subjKeyID) +{ + SecIdentityRef ident = NULL; + CFDictionaryRef query = NULL; + CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull); + + const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef }; + const void *values[] = { kSecClassIdentity, subjectkeyid, kCFBooleanTrue }; + query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL); + require_noerr_quiet(SecItemCopyMatching(query, (CFTypeRef*)&ident), out); + +out: + if (query) + CFRelease(query); + if (subjectkeyid) + CFRelease(subjectkeyid); + + return ident; +} + + + +SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey) +{ + CFRetain(pubKey); + return pubKey; +} + +void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey) +{ + CFRelease(pubKey); +} + +SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey) +{ + CFRetain(privKey); + return privKey; +} + +void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey) +{ + CFRelease(privKey); +} + +void CERT_DestroyCertificate(SecCertificateRef cert) +{ + CFRelease(cert); +} + +SecCertificateRef CERT_DupCertificate(SecCertificateRef cert) +{ + CFRetain(cert); + return cert; +} + +SECStatus +WRAP_PubWrapSymKey(SecPublicKeyRef publickey, + SecSymmetricKeyRef bulkkey, + SecAsn1Item * encKey) +{ + return SecKeyEncrypt(publickey, kSecPaddingPKCS1, + CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey), + encKey->Data, &encKey->Length); +} + +SecSymmetricKeyRef +WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag) +{ + size_t bulkkey_size = encKey->Length; + uint8_t bulkkey_buffer[bulkkey_size]; + if (SecKeyDecrypt(privkey, kSecPaddingPKCS1, + encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size)) + return NULL; + + CFDataRef bulkkey = CFDataCreate(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size); + return (SecSymmetricKeyRef)bulkkey; +} + + +bool +CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial) +{ + do { + CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert); + if (!cert_issuer) + break; + if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) || + memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) { + CFRelease(cert_issuer); + break; + } + CFRelease(cert_issuer); + CFDataRef cert_serial = SecCertificateCopySerialNumber(cert); + if (!cert_serial) + break; + if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) || + memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) { + CFRelease(cert_serial); + break; + } + CFRelease(cert_serial); + return true; + } while(0); + return false; +}