/*
- * crypto-embedded.c
- * libsecurity_smime
+ * Copyright (c) 2008-2011,2013,2015 Apple Inc. All Rights Reserved.
*
- * Created by Conrad Sauerwald on 2/7/08.
- * Copyright (c) 2008-2011,2013 Apple Inc. All Rights Reserved.
+ * @APPLE_LICENSE_HEADER_START@
*
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
*/
#include <stdio.h>
#include <Security/oidsalg.h>
#include <Security/SecPolicy.h>
#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
#include <Security/SecIdentity.h>
#include <Security/SecCertificateInternal.h>
#include <Security/SecKeyPriv.h>
+#include <utilities/SecCFWrappers.h>
#include <CommonCrypto/CommonDigest.h>
#include <AssertMacros.h>
SECStatus
CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs,
- CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
+ CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
{
SecTrustRef trust = NULL;
OSStatus rv;
rv = SecTrustSetVerifyDate(trust, verifyDate);
CFRelease(verifyDate);
if (rv)
- goto loser;
+ goto loser;
if (trustRef)
{
- *trustRef = trust;
+ *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;
- }
+ 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;
+ }
}
return SECSuccess;
loser:
if (trust)
- CFRelease(trust);
+ CFRelease(trust);
return rv;
}
+static CF_RETURNS_RETAINED CFTypeRef CERT_FindItemInAllAvailableKeychains(CFDictionaryRef query) {
+ CFTypeRef item = NULL;
+ CFMutableDictionaryRef q = NULL;
+ CFDictionaryRef whoAmI = NULL;
+ CFErrorRef error = NULL;
+ CFDataRef musr = NULL;
+ const uint8_t activeUserUuid[16] = "\xA7\x5A\x3A\x35\xA5\x57\x4B\x10\xBE\x2E\x83\x94\x7E\x4A\x34\x72";
+
+ /* Do the standard keychain query */
+ require_quiet(errSecItemNotFound == SecItemCopyMatching(query, &item), out);
+
+ /* No item found. Can caller use the system keychain? */
+ whoAmI = _SecSecuritydCopyWhoAmI(&error);
+ require_quiet(NULL == error && whoAmI && CFDictionaryGetValue(whoAmI, CFSTR("status")), out);
+ musr = CFDictionaryGetValue(whoAmI, CFSTR("musr"));
+ /* Caller has system-keychain entitlement, is in multi-user mode, and is an active user. */
+ if (CFDictionaryGetValue(whoAmI, CFSTR("system-keychain")) && musr &&
+ (16 == CFDataGetLength(musr)) && (0 == memcmp(activeUserUuid,CFDataGetBytePtr(musr),12))) {
+ q = CFDictionaryCreateMutableCopy(NULL, CFDictionaryGetCount(query) + 1, query);
+ CFDictionaryAddValue(q, kSecUseSystemKeychain, kCFBooleanTrue);
+ SecItemCopyMatching(q, &item);
+ }
+
+out:
+ if (q)
+ CFRelease(q);
+ if (whoAmI)
+ CFRelease(whoAmI);
+ if (error)
+ CFRelease(error);
+
+ return item;
+}
SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray,
char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win)
const void *values[] = { kSecClassCertificate, nickname_cfstr };
CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL);
CFTypeRef result = NULL;
- SecItemCopyMatching(query, &result);
+ result = CERT_FindItemInAllAvailableKeychains(query);
CFRelease(query);
CFRelease(nickname_cfstr);
return (SecCertificateRef)result;
}
-CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
+CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot, Boolean mustIncludeRoot)
{
CFMutableArrayRef certs = NULL;
SecPolicyRef policy = NULL;
CFArrayRef wrappedCert = NULL;
policy = SecPolicyCreateBasicX509();
- if (!policy)
+ if (!policy) {
goto out;
+ }
wrappedCert = CERT_CertListFromCert(cert);
- if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust))
+ if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust)) {
goto out;
+ }
SecTrustResultType result;
- if (SecTrustEvaluate(trust, &result))
+ if (SecTrustEvaluate(trust, &result)) {
goto out;
+ }
CFIndex idx, count = SecTrustGetCertificateCount(trust);
+
+ /* If we weren't able to build a chain to a self-signed cert, warn. */
+ Boolean isSelfSigned = false;
+ SecCertificateRef lastCert = SecTrustGetCertificateAtIndex(trust, count - 1);
+ if (lastCert && (0 == SecCertificateIsSelfSigned(lastCert, &isSelfSigned)) && !isSelfSigned) {
+ CFStringRef commonName = NULL;
+ (void)SecCertificateCopyCommonName(cert, &commonName);
+ fprintf(stderr, "Warning: unable to build chain to self-signed root for signer \"%s\"\n",
+ commonName ? CFStringGetCStringPtr(commonName, kCFStringEncodingUTF8) : "");
+ if (commonName) { CFRelease(commonName); }
+
+ // we don't have a root, so if the caller required one, fail
+ if (mustIncludeRoot) {
+ goto out;
+ }
+ }
+
+ /* We don't drop the root if there is only 1 certificate in the chain. */
+ if (isSelfSigned && !includeRoot && count > 1) {
+ count--;
+ }
certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
- for(idx = 0; idx < count; idx++)
+ for(idx = 0; idx < count; idx++) {
CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
-
+ }
+
out:
- if (trust) CFRelease(trust);
- if (policy) CFRelease(policy);
- if (wrappedCert) CFRelease(wrappedCert);
+ if (trust) { CFRelease(trust); }
+ if (policy) { CFRelease(policy); }
+ if (wrappedCert) { CFRelease(wrappedCert); }
return certs;
}
-CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
+CF_RETURNS_RETAINED CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
{
const void *value = cert;
return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
// Extract a public key object from a SubjectPublicKeyInfo
SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
{
- return SecCertificateCopyPublicKey(cert);
+ return SecCertificateCopyKey(cert);
}
// Extract the issuer and serial number from a certificate
void *mark;
mark = PORT_ArenaMark(pl);
- CFDataRef serial_data = NULL;
CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
- if (!issuer_data)
+ CFDataRef serial_data = SecCertificateCopySerialNumberData(cert, NULL);
+ if (!issuer_data || !serial_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. */
+ }
+
+ SecAsn1Item serialNumber = {
+ .Length = CFDataGetLength(serial_data),
+ .Data = (uint8_t *)CFDataGetBytePtr(serial_data)
+ };
+ SecAsn1Item issuer = {
+ .Length = CFDataGetLength(issuer_data),
+ .Data = (uint8_t *)CFDataGetBytePtr(issuer_data)
+ };
+
+ /* Allocate the SecCmsIssuerAndSN struct. */
certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
- if (certIssuerAndSN == NULL)
- goto loser;
+ if (certIssuerAndSN == NULL) {
+ goto loser;
+ }
/* Copy the issuer. */
certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
- if (!certIssuerAndSN->derIssuer.Data)
- goto loser;
+ 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;
+ if (!certIssuerAndSN->serialNumber.Data) {
+ goto loser;
+ }
PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
certIssuerAndSN->serialNumber.Length = serialNumber.Length;
CFRelease(issuer_data);
PORT_ArenaUnmark(pl, mark);
-
+
return certIssuerAndSN;
loser:
- if (serial_data)
- CFRelease(serial_data);
- if (issuer_data)
- CFRelease(issuer_data);
+ CFReleaseNull(serial_data);
+ CFReleaseNull(issuer_data);
PORT_ArenaRelease(pl, mark);
PORT_SetError(SEC_INTERNAL_ONLY);
// 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)
+static CF_RETURNS_RETAINED CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef class, const SecCmsIssuerAndSN *issuerAndSN)
{
CFTypeRef ident = NULL;
CFDictionaryRef query = NULL;
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c);
CFDataRef nic = (cert) ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
if (nic && CFEqual(nic, issuer)) {
- CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
+ CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
if (cert_serial) {
bool found = CFEqual(cert_serial, serial);
CFRelease(cert_serial);
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);
+ ident = CERT_FindItemInAllAvailableKeychains(query);
out:
if (query)
return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
}
-SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused, const SecAsn1Item *subjKeyID)
+// Generate a certificate key from the Subject Key ID, then look it up in the database.
+// Return the cert if found. "subjKeyID" is the Subject Key ID to look for
+static CF_RETURNS_RETAINED CFTypeRef CERT_FindBySubjectKeyID (CFTypeRef keychainOrArray, CFTypeRef class, const SecAsn1Item *subjKeyID)
{
- SecIdentityRef ident = NULL;
- CFDictionaryRef query = NULL;
+ CFTypeRef ident = NULL;
+ CFDictionaryRef query = NULL;
+
+ if (!subjKeyID || !subjKeyID->Data || !subjKeyID->Length) {
+ return NULL;
+ }
+
CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
+ 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);
+ CFDataRef skid = (cert) ? SecCertificateGetSubjectKeyID(cert) : NULL;
+ if (skid && CFEqual(skid, subjectkeyid)) {
+ CFRetain(cert);
+ ident = cert;
+ goto out;
+ }
+ }
+ }
- 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);
+ const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef };
+ const void *values[] = { class, subjectkeyid, kCFBooleanTrue };
+ query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL);
+ ident = CERT_FindItemInAllAvailableKeychains(query);
out:
if (query)
return ident;
}
+SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
+{
+ return (SecIdentityRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassIdentity, subjKeyID);
+}
+
+SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
+{
+ return (SecCertificateRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassCertificate, subjKeyID);
+}
+
SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
return pubKey;
}
-void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
+void SECKEY_DestroyPublicKey(SecPublicKeyRef CF_CONSUMED pubKey)
{
CFRelease(pubKey);
}
encKey->Data, &encKey->Length);
}
+#define MAX_KEY_SIZE 8192/8
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;
+ if (bulkkey_size > MAX_KEY_SIZE) {
+ return NULL;
+ }
+
+ uint8_t *bulkkey_buffer = (uint8_t *)malloc(bulkkey_size);
+ if (!bulkkey_buffer) {
+ return NULL;
+ }
+ if (SecKeyDecrypt(privkey, kSecPaddingPKCS1, encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size)) {
+ return NULL;
+ }
- CFDataRef bulkkey = CFDataCreate(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size);
+ CFDataRef bulkkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size, kCFAllocatorMalloc);
return (SecSymmetricKeyRef)bulkkey;
}
break;
}
CFRelease(cert_issuer);
- CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
+ CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
if (!cert_serial)
break;
if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||