Exemple #1
0
static int32_t ProcessCertificateTypeReturn(CFArrayRef items, SecCertificateRef* pCertOut, SecIdentityRef* pIdentityOut)
{
    assert(pCertOut != nullptr && *pCertOut == nullptr);
    assert(pIdentityOut != nullptr && *pIdentityOut == nullptr);

    if (items == nullptr)
    {
        return kErrOutItemsNull;
    }

    CFIndex itemCount = CFArrayGetCount(items);

    if (itemCount == 0)
    {
        return kErrOutItemsEmpty;
    }

    CFTypeRef bestItem = nullptr;

    for (CFIndex i = 0; i < itemCount; i++)
    {
        CFTypeRef current = CFArrayGetValueAtIndex(items, i);
        auto currentItemType = CFGetTypeID(current);

        if (currentItemType == SecIdentityGetTypeID())
        {
            bestItem = current;
            break;
        }
        else if (bestItem == nullptr && currentItemType == SecCertificateGetTypeID())
        {
            bestItem = current;
        }
    }

    if (bestItem == nullptr)
    {
        return -13;
    }

    if (CFGetTypeID(bestItem) == SecCertificateGetTypeID())
    {
        CFRetain(bestItem);
        *pCertOut = reinterpret_cast<SecCertificateRef>(const_cast<void*>(bestItem));
        return 1;
    }

    if (CFGetTypeID(bestItem) == SecIdentityGetTypeID())
    {
        CFRetain(bestItem);
        *pIdentityOut = reinterpret_cast<SecIdentityRef>(const_cast<void*>(bestItem));

        return 1;
    }

    return -19;
}
/*
 * Store the specified certificate (or, more likely, some platform-dependent
 * reference to it) as the specified principal's signing certificate. Passing
 * in NULL for the client_cert has the effect of deleting the relevant entry
 * in the cert storage.
 */
krb5_error_code krb5_pkinit_set_client_cert_from_signing_cert(
    const char                  *principal,     /* full principal string */
    krb5_pkinit_signing_cert_t  client_cert)
{
    SecIdentityRef idRef = (SecIdentityRef)client_cert;
    SecCertificateRef certRef = NULL;
    OSStatus ortn;
    krb5_error_code ourRtn = 0;

    if (NULL != idRef) {
        if (CFGetTypeID(idRef) != SecIdentityGetTypeID()) {
            ourRtn = KRB5KRB_ERR_GENERIC;
            goto fin;
        }
        /* Get the cert */
        ortn = SecIdentityCopyCertificate(idRef, &certRef);
        if (ortn) {
            pkiCssmErr("SecIdentityCopyCertificate", ortn);
            ourRtn = KRB5KRB_ERR_GENERIC;
            goto fin;
        }
    }
    ourRtn = krb5_pkinit_set_client_cert(principal, (krb5_pkinit_cert_t)certRef);
fin:
    if (certRef)
        CFRelease(certRef);
    return ourRtn;
}
/*
 * Assume incoming identity contains a root (e.g., created by
 * certtool) and add that cert to ST's trusted anchors. This
 * enables ST's verify of the incoming chain to succeed without 
 * a kludgy "AllowAnyRoot" specification.
 */
OSStatus addIdentityAsTrustedRoot(
	SSLContextRef 	ctx,
	CFArrayRef		identArray)
{
	CFIndex numItems = CFArrayGetCount(identArray);
	if(numItems == 0) {
		printf("***addIdentityAsTrustedRoot: empty identArray\n");
		return errSecParam;
	}
	
	/* Root should be the last item - could be identity, could be cert */
	CFTypeRef theItem = CFArrayGetValueAtIndex(identArray, numItems - 1);
	if(CFGetTypeID(theItem) == SecIdentityGetTypeID()) {
		/* identity */
		SecCertificateRef certRef;
		OSStatus ortn = SecIdentityCopyCertificate(
			(SecIdentityRef)theItem, &certRef);
		if(ortn) {
			cssmPerror("SecIdentityCopyCertificate", ortn);
			printf("***Error gettting cert from identity\n");
			return ortn;
		}
		ortn = addTrustedSecCert(ctx, certRef, false);
		CFRelease(certRef);
		return ortn;
	}
	else if(CFGetTypeID(theItem) == SecCertificateGetTypeID()) {
		/* certificate */
		return addTrustedSecCert(ctx, (SecCertificateRef)theItem, false);
	}
	else {
		printf("***Bogus item in identity array\n");
		return errSecParam;
	}
}
Exemple #4
0
extern "C" int32_t
AppleCryptoNative_X509DemuxAndRetainHandle(CFTypeRef handle, SecCertificateRef* pCertOut, SecIdentityRef* pIdentityOut)
{
    if (pCertOut != nullptr)
        *pCertOut = nullptr;
    if (pIdentityOut != nullptr)
        *pIdentityOut = nullptr;

    if (handle == nullptr || pCertOut == nullptr || pIdentityOut == nullptr)
        return kErrorBadInput;

    auto objectType = CFGetTypeID(handle);
    void* nonConstHandle = const_cast<void*>(handle);

    if (objectType == SecIdentityGetTypeID())
    {
        *pIdentityOut = reinterpret_cast<SecIdentityRef>(nonConstHandle);
    }
    else if (objectType == SecCertificateGetTypeID())
    {
        *pCertOut = reinterpret_cast<SecCertificateRef>(nonConstHandle);
    }
    else
    {
        return 0;
    }

    CFRetain(handle);
    return 1;
}
Exemple #5
0
static CFDictionaryRef
SecItemCopyAttributeDictionary(CFTypeRef ref) {
	CFDictionaryRef refDictionary = NULL;
	CFTypeID typeID = CFGetTypeID(ref);
	if (typeID == SecKeyGetTypeID()) {
		refDictionary = SecKeyCopyAttributeDictionary((SecKeyRef)ref);
	} else if (typeID == SecCertificateGetTypeID()) {
		refDictionary =
			SecCertificateCopyAttributeDictionary((SecCertificateRef)ref);
	} else if (typeID == SecIdentityGetTypeID()) {
        assert(false);
        SecIdentityRef identity = (SecIdentityRef)ref;
        SecCertificateRef cert = NULL;
        SecKeyRef key = NULL;
        if (!SecIdentityCopyCertificate(identity, &cert) &&
            !SecIdentityCopyPrivateKey(identity, &key)) 
        {
            CFDataRef data = SecCertificateCopyData(cert);
            CFDictionaryRef key_dict = SecKeyCopyAttributeDictionary(key);
            
            if (key_dict && data) {
                refDictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, key_dict);
                CFDictionarySetValue((CFMutableDictionaryRef)refDictionary, 
                    CFSTR(CERTIFICATE_DATA_COLUMN_LABEL), data);
            }
            CFReleaseNull(key_dict);
            CFReleaseNull(data);
        }
        CFReleaseNull(cert);
        CFReleaseNull(key);
    } else {
		refDictionary = NULL;
	}
	return refDictionary;
}
/* 
 * Specify signers of the CMS message; implies that the message will be signed. 
 */
OSStatus CMSEncoderAddSigners(
	CMSEncoderRef		cmsEncoder,
	CFTypeRef			signerOrArray)
{
	if(cmsEncoder == NULL) {
		return errSecParam;
	}
	if(cmsEncoder->encState != ES_Init) {
		return errSecParam;
	}
	return cmsAppendToArray(signerOrArray, &cmsEncoder->signers, SecIdentityGetTypeID());
}
static int do_keychain_import(
	SecKeychainRef		kcRef,
	CFDataRef			inData,
	SecExternalFormat   externFormat,
	SecExternalItemType itemType,
	SecAccessRef		access,
	Boolean				nonExtractable,
	const char			*passphrase,
	const char			*fileName,
	char				**attrNames,
	char				**attrValues,
	unsigned			numExtendedAttributes)
{
	SecKeyImportExportParameters	keyParams;
	OSStatus		ortn;
	CFStringRef		fileStr;
	CFArrayRef		outArray = NULL;
	int				result = 0;
	int				numCerts = 0;
	int				numKeys = 0;
	int				numIdentities = 0;
	int				tryCount = 0;
	CFIndex			dex;
	CFIndex			numItems = 0;
	CFStringRef		passStr = NULL;
	CFStringRef		promptStr = NULL;
	CFStringRef		retryStr = NULL;

	/*
	 * Specify some kind of passphrase in case caller doesn't know this
	 * is a wrapped object
	 */
	memset(&keyParams, 0, sizeof(SecKeyImportExportParameters));
	keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
	if(passphrase != NULL) {
		passStr = CFStringCreateWithCString(NULL, passphrase, kCFStringEncodingASCII);
		keyParams.passphrase = passStr;
	}
	else {
		keyParams.flags = kSecKeySecurePassphrase;
	}
	if(nonExtractable) {
        // explicitly set the key attributes, omitting the CSSM_KEYATTR_EXTRACTABLE bit
        keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE;
    }
	keyParams.accessRef = access;

	fileStr = CFStringCreateWithCString(NULL, fileName, kCFStringEncodingUTF8);
	if (fileStr) {
		CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, fileStr, kCFURLPOSIXPathStyle, FALSE);
		if (fileURL) {
			CFStringRef nameStr = CFURLCopyLastPathComponent(fileURL);
			if (nameStr) {
				safe_CFRelease(&fileStr);
				fileStr = nameStr;
			}
			safe_CFRelease(&fileURL);
		}
	}
	promptStr = CFStringCreateWithFormat(NULL, NULL, KC_IMPORT_KEY_PASSWORD_MESSAGE, fileStr);
	retryStr = CFStringCreateWithFormat(NULL, NULL, KC_IMPORT_KEY_PASSWORD_RETRYMESSAGE, fileStr);

	while (TRUE)
	{
		keyParams.alertPrompt = (tryCount == 0) ? promptStr : retryStr;

		ortn = SecKeychainItemImport(inData,
									 fileStr,
									 &externFormat,
									 &itemType,
									 0,		/* flags not used (yet) */
									 &keyParams,
									 kcRef,
									 &outArray);

		if(ortn) {
			if (ortn == errSecPkcs12VerifyFailure && ++tryCount < 3) {
				continue;
			}
			sec_perror("SecKeychainItemImport", ortn);
			result = 1;
			goto cleanup;
		}
		break;
	}

	/*
	 * Parse returned items & report to user
	 */
	if(outArray == NULL) {
		sec_error("No keychain items found");
		result = 1;
		goto cleanup;
	}
	numItems = CFArrayGetCount(outArray);
	for(dex=0; dex<numItems; dex++) {
		CFTypeRef item = CFArrayGetValueAtIndex(outArray, dex);
		CFTypeID itemType = CFGetTypeID(item);
		if(itemType == SecIdentityGetTypeID()) {
			numIdentities++;
		}
		else if(itemType == SecCertificateGetTypeID()) {
			numCerts++;
		}
		else if(itemType == SecKeyGetTypeID()) {
			numKeys++;
		}
		else {
			sec_error("Unexpected item type returned from SecKeychainItemImport");
			result = 1;
			goto cleanup;
		}
	}
	if(numIdentities) {
		char *str;
		if(numIdentities > 1) {
			str = "identities";
		}
		else {
			str = "identity";
		}
		fprintf(stdout, "%d %s imported.\n", numIdentities, str);
	}
	if(numKeys) {
		char *str;
		if(numKeys > 1) {
			str = "keys";
		}
		else {
			str = "key";
		}
		fprintf(stdout, "%d %s imported.\n", numKeys, str);
	}
	if(numCerts) {
		char *str;
		if(numCerts > 1) {
			str = "certificates";
		}
		else {
			str = "certificate";
		}
		fprintf(stdout, "%d %s imported.\n", numCerts, str);
	}

	/* optionally apply extended attributes */
	if(numExtendedAttributes) {
		unsigned attrDex;
		for(attrDex=0; attrDex<numExtendedAttributes; attrDex++) {
			CFStringRef attrNameStr = CFStringCreateWithCString(NULL, attrNames[attrDex],
				kCFStringEncodingASCII);
			CFDataRef attrValueData = CFDataCreate(NULL, (const UInt8 *)attrValues[attrDex],
				strlen(attrValues[attrDex]));
			for(dex=0; dex<numItems; dex++) {
				SecKeychainItemRef itemRef =
					(SecKeychainItemRef)CFArrayGetValueAtIndex(outArray, dex);
				ortn = SecKeychainItemSetExtendedAttribute(itemRef, attrNameStr, attrValueData);
				if(ortn) {
					cssmPerror("SecKeychainItemSetExtendedAttribute", ortn);
					result = 1;
					break;
				}
			}	/* for each imported item */
			CFRelease(attrNameStr);
			CFRelease(attrValueData);
			if(result) {
				break;
			}
		}	/* for each extended attribute */
	}

cleanup:
	safe_CFRelease(&fileStr);
	safe_CFRelease(&outArray);
	safe_CFRelease(&passStr);
	safe_CFRelease(&promptStr);
	safe_CFRelease(&retryStr);

	return result;
}
Exemple #8
0
static CFArrayRef				/* O - Array of certificates */
copy_cdsa_certificate(
    cupsd_client_t *con)			/* I - Client connection */
{
  OSStatus		err;		/* Error info */
  SecKeychainRef	keychain = NULL;/* Keychain reference */
  SecIdentitySearchRef	search = NULL;	/* Search reference */
  SecIdentityRef	identity = NULL;/* Identity */
  CFArrayRef		certificates = NULL;
					/* Certificate array */
  SecPolicyRef		policy = NULL;	/* Policy ref */
  CFStringRef		servername = NULL;
					/* Server name */
  CFMutableDictionaryRef query = NULL;	/* Query qualifiers */
  CFArrayRef		list = NULL;	/* Keychain list */
#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  char			localname[1024];/* Local hostname */
#    endif /* HAVE_DNSSD || HAVE_AVAHI */


  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "copy_cdsa_certificate: Looking for certs for \"%s\".",
		  con->servername);

  if ((err = SecKeychainOpen(ServerCertificate, &keychain)))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)",
	            ServerCertificate, cssmErrorString(err), (int)err);
    goto cleanup;
  }

  servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername,
					 kCFStringEncodingUTF8);

  policy = SecPolicyCreateSSL(1, servername);

  if (servername)
    CFRelease(servername);

  if (!policy)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
    goto cleanup;
  }

  if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
					  &kCFTypeDictionaryKeyCallBacks,
					  &kCFTypeDictionaryValueCallBacks)))
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary");
    goto cleanup;
  }

  list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1,
                       &kCFTypeArrayCallBacks);

  CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
  CFDictionaryAddValue(query, kSecMatchPolicy, policy);
  CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
  CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne);
  CFDictionaryAddValue(query, kSecMatchSearchList, list);

  CFRelease(list);

  err = SecItemCopyMatching(query, (CFTypeRef *)&identity);

#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  if (err && DNSSDHostName)
  {
   /*
    * Search for the connection server name failed; try the DNS-SD .local
    * hostname instead...
    */

    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);

    cupsdLogMessage(CUPSD_LOG_DEBUG,
		    "copy_cdsa_certificate: Looking for certs for \"%s\".",
		    localname);

    servername = CFStringCreateWithCString(kCFAllocatorDefault, localname,
					   kCFStringEncodingUTF8);

    CFRelease(policy);

    policy = SecPolicyCreateSSL(1, servername);

    if (servername)
      CFRelease(servername);

    if (!policy)
    {
      cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference");
      goto cleanup;
    }

    CFDictionarySetValue(query, kSecMatchPolicy, policy);

    err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
  }
#    endif /* HAVE_DNSSD || HAVE_AVAHI */

  if (err)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG,
		    "Cannot find signing key in keychain \"%s\": %s (%d)",
		    ServerCertificate, cssmErrorString(err), (int)err);
    goto cleanup;
  }

  if (CFGetTypeID(identity) != SecIdentityGetTypeID())
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure.");
    goto cleanup;
  }

  if ((certificates = CFArrayCreate(NULL, (const void **)&identity,
				  1, &kCFTypeArrayCallBacks)) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array");
    goto cleanup;
  }

  cleanup :

  if (keychain)
    CFRelease(keychain);
  if (search)
    CFRelease(search);
  if (identity)
    CFRelease(identity);

  if (policy)
    CFRelease(policy);
  if (query)
    CFRelease(query);

  return (certificates);
}
OSStatus
parseIncomingCerts(
	SSLContext			*ctx,
	CFArrayRef			certs,
	CFArrayRef			*destCertChain,	/* &ctx->{localCertChain,encryptCertChain} */
	SSLPubKey			**sslPubKey,	/* &ctx->signingPubKey, etc. */
	SSLPrivKey			**sslPrivKey,	/* &ctx->signingPrivKeyRef, etc. */
	CFIndex				*signerAlg)		/* optional */
{
	OSStatus			ortn;
	CFIndex				ix, numCerts;
	SecIdentityRef 		identity;
	CFMutableArrayRef	certChain = NULL;	/* Retained */
	SecCertificateRef	leafCert = NULL;	/* Retained */
	SecKeyRef			pubKey = NULL;		/* Retained */
	SecKeyRef           privKey = NULL;		/* Retained */
	SecTrustRef         trust = NULL;		/* Retained */
	SecTrustResultType	trustResult;

	assert(ctx != NULL);
	assert(destCertChain != NULL);		/* though its referent may be NULL */
	assert(sslPubKey != NULL);
	assert(sslPrivKey != NULL);

	if (certs == NULL) {
		sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
		ortn = errSSLBadCert;
		goto errOut;
	}
	numCerts = CFArrayGetCount(certs);
	if (numCerts == 0) {
		sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
		ortn = errSSLBadCert;
		goto errOut;
	}

	/*
	 * Certs[0] is an SecIdentityRef from which we extract subject cert,
	 * privKey, pubKey.
	 *
	 * 1. ensure the first element is a SecIdentityRef.
	 */
	identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
	if (identity == NULL) {
		sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
		ortn = paramErr;
		goto errOut;
	}
	if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
		sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
		ortn = paramErr;
		goto errOut;
	}

	/*
	 * 2. Extract cert, keys and convert to local format.
	 */
	ortn = SecIdentityCopyCertificate(identity, &leafCert);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
		goto errOut;
	}

	/* Fetch private key from identity */
	ortn = SecIdentityCopyPrivateKey(identity, &privKey);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
			(int)ortn);
		goto errOut;
	}

	/* Convert the input array of SecIdentityRef at the start to an array of
	   all certificates. */
	certChain = CFArrayCreateMutable(kCFAllocatorDefault, numCerts,
		&kCFTypeArrayCallBacks);
	if (!certChain) {
		ortn = memFullErr;
		goto errOut;
	}
	CFArrayAppendValue(certChain, leafCert);
	for (ix = 1; ix < numCerts; ++ix) {
		SecCertificateRef intermediate =
			(SecCertificateRef)CFArrayGetValueAtIndex(certs, ix);
		if (intermediate == NULL) {
			sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
			ortn = paramErr;
			goto errOut;
		}
		if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
			sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
			ortn = paramErr;
			goto errOut;
		}

		CFArrayAppendValue(certChain, intermediate);
	}

	/* Obtain public key from cert */
#if TARGET_OS_IOS
	ortn = SecTrustCreateWithCertificates(certChain, NULL, &trust);
#else
	{
		SecPolicyRef policy = SecPolicyCreateBasicX509();
		ortn = SecTrustCreateWithCertificates(certChain, policy, &trust);
		CFReleaseSafe(policy);
		if (!ortn) {
			/* We are only interested in getting the public key from the leaf
			 * cert here, so for best performance, don't try to build a chain
			 * or search any keychains.
			 */
			CFArrayRef emptyArray = CFArrayCreate(NULL, NULL, 0, NULL);
			(void)SecTrustSetAnchorCertificates(trust, emptyArray);
			(void)SecTrustSetKeychains(trust, emptyArray);
			CFReleaseSafe(emptyArray);
		}
	}
#endif
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecTrustCreateWithCertificates err %d\n",
			(int)ortn);
		goto errOut;
	}
	ortn = SecTrustEvaluate(trust, &trustResult);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n",
			(int)ortn);
		goto errOut;
	}
	pubKey = SecTrustCopyPublicKey(trust);
	if (pubKey == NULL) {
		sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n");
		ortn = -67712; // errSecInvalidKeyRef
		goto errOut;
	}

	/* SUCCESS */
errOut:
	CFReleaseSafe(trust);
	CFReleaseSafe(leafCert);
	CFReleaseSafe(*destCertChain);
    sslFreePubKey(sslPubKey);
    sslFreePrivKey(sslPrivKey);

	if (ortn) {
		CFReleaseSafe(certChain);
		CFReleaseSafe(pubKey);
		CFReleaseSafe(privKey);

		*destCertChain = NULL;
	} else {
		*destCertChain = certChain;
		*sslPubKey = (SSLPubKey*)pubKey;
		*sslPrivKey = (SSLPrivKey*)privKey;
	}

	return ortn;
}
OSStatus
parseIncomingCerts(
	SSLContext		*ctx,
	CFArrayRef		certs,
	SSLCertificate	**destCert,		/* &ctx->{localCert,encryptCert} */
	CSSM_KEY_PTR	*pubKey,		/* &ctx->signingPubKey, etc. */
	SecKeyRef		*privKeyRef,	/* &ctx->signingPrivKeyRef, etc. */
	CSSM_ALGORITHMS	*signerAlg)		/* optional */
{
	CFIndex				numCerts;
	CFIndex				cert;
	SSLCertificate		*certChain = NULL;
	SSLCertificate		*thisSslCert;
	OSStatus			ortn;
	SecIdentityRef 		identity;
	SecCertificateRef	certRef;
	SecKeyRef			keyRef;
	CSSM_DATA			certData;
	CSSM_CL_HANDLE		clHand;		// carefully derive from a SecCertificateRef
	CSSM_RETURN			crtn;
	CSSM_KEY_PTR        *pubKey;
	SecKeyRef           *privKeyRef;

	assert(ctx != NULL);
	assert(destCert != NULL);		/* though its referent may be NULL */
	assert(sslPubKey != NULL);
	assert(sslPrivKeyRef != NULL);

	pubKey = &sslPubKey->key;
	privKeyRef = &sslPrivKey->key;

	sslDeleteCertificateChain(*destCert, ctx);
	*destCert = NULL;
	*pubKey   = NULL;
	*privKeyRef = NULL;

	if(certs == NULL) {
		sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
		return errSSLBadCert;
	}
	numCerts = CFArrayGetCount(certs);
	if(numCerts == 0) {
		sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
		return errSSLBadCert;
	}

	/*
	 * Certs[0] is an SecIdentityRef from which we extract subject cert,
	 * privKeyRef, pubKey.
	 *
	 * 1. ensure the first element is a SecIdentityRef.
	 */
	identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
	if(identity == NULL) {
		sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
		return paramErr;
	}
	if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
		sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
		return paramErr;
	}

	/*
	 * 2. Extract cert, keys and convert to local format.
	 */
	ortn = SecIdentityCopyCertificate(identity, &certRef);
	if(ortn) {
		sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
		return ortn;
	}
	ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
	if(ortn) {
		sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
		return ortn;
	}
	/* enqueue onto head of cert chain */
	thisSslCert->next = certChain;
	certChain = thisSslCert;

	if(signerAlg != NULL) {
		ortn = sslCertSignerAlg(certRef, signerAlg);
		if(ortn) {
			return ortn;
		}
	}

	/* fetch private key from identity */
	ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
	if(ortn) {
		sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
			(int)ortn);
		return ortn;
	}
	*privKeyRef = keyRef;

	/* obtain public key from cert */
	ortn = SecCertificateGetCLHandle(certRef, &clHand);
	if(ortn) {
		sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
			(int)ortn);
		return ortn;
	}
	certData.Data = thisSslCert->derCert.data;
	certData.Length = thisSslCert->derCert.length;
	crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey);
	if(crtn) {
		sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
		return (OSStatus)crtn;
	}

	/* OK, that's the subject cert. Fetch optional remaining certs. */
	/*
	 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
	 * Incoming certs have root last; SSLCertificate chain has root
	 * first.
	 */
	for(cert=1; cert<numCerts; cert++) {
		certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
		if(certRef == NULL) {
			sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
			return paramErr;
		}
		if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
			sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
			return paramErr;
		}

		/* Extract cert, convert to local format.
		*/
		ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
		if(ortn) {
			sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
			return ortn;
		}
		/* enqueue onto head of cert chain */
		thisSslCert->next = certChain;
		certChain = thisSslCert;
	}

	/* SUCCESS */
	*destCert = certChain;
	return noErr;

	/* free certChain, everything in it, other vars, return ortn */
	sslDeleteCertificateChain(certChain, ctx);
	/* FIXME - anything else? */
	return ortn;
}
Exemple #11
0
int findFirstEncryptionPublicKeyOnToken(SecKeyRef *publicKey, SecKeychainRef *keychainRef, CFDataRef *label)
{
	if (!publicKey || !keychainRef)
		return paramErr;

	OSStatus status = noErr;
	CFArrayRef identityArray = NULL;
	SecKeyRef tmpKeyRef = NULL;
	SecCertificateRef certificate = NULL;
	SecKeychainRef tmpKeychainRef = NULL;
		
	try
	{
		status = findEncryptionIdentities((CFTypeRef *)&identityArray);
		if (status)
			MacOSError::throwMe(status);

		if (!identityArray || 
			(CFGetTypeID(identityArray)!=CFArrayGetTypeID()) ||
			(CFArrayGetCount(identityArray)==0))
			MacOSError::throwMe(paramErr);

		CFTypeRef tmpref = CFArrayGetValueAtIndex(identityArray, 0);
		if (CFGetTypeID(tmpref)!=SecIdentityGetTypeID())
			MacOSError::throwMe(paramErr);
			
		status = SecIdentityCopyCertificate(SecIdentityRef(tmpref), &certificate);
		if (status)
			MacOSError::throwMe(status);

		if (!certificate)
			MacOSError::throwMe(errKCItemNotFound);
		
		status = findCertificatePublicKeyHash(certificate, label);
		if (status)
			MacOSError::throwMe(status);

		status = SecKeychainItemCopyKeychain(SecKeychainItemRef(certificate), &tmpKeychainRef);
		if (status)
			MacOSError::throwMe(status);

		status = SecCertificateCopyPublicKey(certificate, &tmpKeyRef);
		if (status)
			MacOSError::throwMe(status);
		
		// Found an encryption key
		*publicKey = tmpKeyRef;
		*keychainRef = tmpKeychainRef;
	}
	catch (const MacOSError &err)
	{
		status = err.osStatus();
		cssmPerror("findFirstEncryptionPublicKeyOnToken", status);
	}
	catch (...)
	{
		fprintf(stderr, "findFirstEncryptionPublicKeyOnToken: unknown exception\n");
		status = errKCItemNotFound;
	}
	
	if (status)
	{
		if (identityArray)
			CFRelease(identityArray);
		if (certificate)
			CFRelease(certificate);
	}

	if (identityArray)
		CFRelease(identityArray);
	if (certificate)
		CFRelease(certificate);
	
	return status;
}
/*
 * Given an open keychain, find a SecIdentityRef and munge it into
 * a CFArrayRef required by SSLSetCertificate().
 */
CFArrayRef sslKcRefToCertArray(
	SecKeychainRef		kcRef,
	bool                encryptOnly,
	bool                completeCertChain,
	const char			*trustedAnchorFile)
{
	/* quick check to make sure the keychain exists */
	SecKeychainStatus kcStat;
	OSStatus ortn = SecKeychainGetStatus(kcRef, &kcStat);
	if(ortn) {
		printSslErrStr("SecKeychainGetStatus", ortn);
		printf("Can not open keychain. Aborting.\n");
		return nil;
	}
	
	/*
	 * Search for "any" identity matching specified key use; 
	 * in this app, we expect there to be exactly one. 
	 */
	SecIdentitySearchRef srchRef = nil;
	ortn = SecIdentitySearchCreate(kcRef, 
		encryptOnly ? CSSM_KEYUSE_DECRYPT : CSSM_KEYUSE_SIGN,
		&srchRef);
	if(ortn) {
		printf("SecIdentitySearchCreate returned %d.\n", (int)ortn);
		printf("Cannot find signing key in keychain. Aborting.\n");
		return nil;
	}
	SecIdentityRef identity = nil;
	ortn = SecIdentitySearchCopyNext(srchRef, &identity);
	if(ortn) {
		printf("SecIdentitySearchCopyNext returned %d.\n", (int)ortn);
		printf("Cannot find signing key in keychain. Aborting.\n");
		return nil;
	}
	if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
		printf("SecIdentitySearchCopyNext CFTypeID failure!\n");
		return nil;
	}

	/* 
	 * Found one. 
	 */
	if(completeCertChain) {
		/* 
		 * Place it and the other certs needed to verify it -
		 * up to but not including the root - in a CFArray.
		 */
		SecCertificateRef anchorCert = NULL;
		if(trustedAnchorFile) {
			ortn = sslReadAnchor(trustedAnchorFile, &anchorCert);
			if(ortn) {
				printf("***Error reading anchor file\n");
			}
		}
		CFArrayRef ca;
		ortn = sslCompleteCertChain(identity, anchorCert, false, &ca);
		if(anchorCert) {
			CFRelease(anchorCert);
		}
		return ca;
	}
	else {
		/* simple case, just this one identity */
		CFArrayRef ca = CFArrayCreate(NULL,
			(const void **)&identity,
			1,
			NULL);
		if(ca == nil) {
			printf("CFArrayCreate error\n");
		}
		return ca;
	}
}
Exemple #13
0
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert,
                                                            SecKeyRef privateKey,
                                                            SecKeychainRef targetKeychain,
                                                            SecIdentityRef* pIdentityOut,
                                                            int32_t* pOSStatus)
{
    if (pIdentityOut != nullptr)
        *pIdentityOut = nullptr;
    if (pOSStatus != nullptr)
        *pOSStatus = noErr;

    if (cert == nullptr || privateKey == nullptr || targetKeychain == nullptr || pIdentityOut == nullptr ||
        pOSStatus == nullptr)
    {
        return -1;
    }

    SecKeychainRef keyKeychain = nullptr;

    OSStatus status = SecKeychainItemCopyKeychain(reinterpret_cast<SecKeychainItemRef>(privateKey), &keyKeychain);
    SecKeychainItemRef itemCopy = nullptr;

    // This only happens with an ephemeral key, so the keychain we're adding it to is temporary.
    if (status == errSecNoSuchKeychain)
    {
        status = AddKeyToKeychain(privateKey, targetKeychain);
    }

    if (itemCopy != nullptr)
    {
        CFRelease(itemCopy);
    }

    CFMutableDictionaryRef query = nullptr;

    if (status == noErr)
    {
        query = CFDictionaryCreateMutable(
            kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

        if (query == nullptr)
        {
            status = errSecAllocate;
        }
    }

    CFArrayRef searchList = nullptr;

    if (status == noErr)
    {
        searchList = CFArrayCreate(
            nullptr, const_cast<const void**>(reinterpret_cast<void**>(&targetKeychain)), 1, &kCFTypeArrayCallBacks);

        if (searchList == nullptr)
        {
            status = errSecAllocate;
        }
    }

    CFArrayRef itemMatch = nullptr;

    if (status == noErr)
    {
        itemMatch = CFArrayCreate(
            nullptr, const_cast<const void**>(reinterpret_cast<void**>(&cert)), 1, &kCFTypeArrayCallBacks);

        if (itemMatch == nullptr)
        {
            status = errSecAllocate;
        }
    }

    CFTypeRef result = nullptr;

    if (status == noErr)
    {
        CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
        CFDictionarySetValue(query, kSecMatchSearchList, searchList);
        CFDictionarySetValue(query, kSecMatchItemList, itemMatch);
        CFDictionarySetValue(query, kSecClass, kSecClassIdentity);

        status = SecItemCopyMatching(query, &result);

        if (status != noErr && result != nullptr)
        {
            CFRelease(result);
            result = nullptr;
        }

        bool added = false;

        if (status == errSecItemNotFound)
        {
            status = SecCertificateAddToKeychain(cert, targetKeychain);

            added = (status == noErr);
        }

        if (result == nullptr && status == noErr)
        {
            status = SecItemCopyMatching(query, &result);
        }

        if (result != nullptr && status == noErr)
        {

            if (CFGetTypeID(result) != SecIdentityGetTypeID())
            {
                status = errSecItemNotFound;
            }
            else
            {
                SecIdentityRef identity = reinterpret_cast<SecIdentityRef>(const_cast<void*>(result));
                CFRetain(identity);
                *pIdentityOut = identity;
            }
        }

        if (added)
        {
            // The same query that was used to find the identity can be used
            // to find/delete the certificate, as long as we fix the class to just the cert.
            CFDictionarySetValue(query, kSecClass, kSecClassCertificate);

            // Ignore the output status, there's no point in telling the user
            // that the cleanup failed, since that just makes them have a dirty keychain
            // AND their program didn't work.
            SecItemDelete(query);
        }
    }

    if (result != nullptr)
        CFRelease(result);

    if (itemMatch != nullptr)
        CFRelease(itemMatch);

    if (searchList != nullptr)
        CFRelease(searchList);

    if (query != nullptr)
        CFRelease(query);

    if (keyKeychain != nullptr)
        CFRelease(keyKeychain);

    *pOSStatus = status;
    return status == noErr;
}
static void tests(void)
{
    CFDataRef message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
        _user_one_p12, sizeof(_user_one_p12), kCFAllocatorNull);
    CFArrayRef items = NULL;
    SecCertificateRef cert = NULL;
    SecKeyRef pkey = NULL;

    is_status(SecPKCS12Import(message, NULL, NULL), errSecAuthFailed,
        "try null password on a known good p12");

    CFStringRef password = CFSTR("user-one");
    CFDictionaryRef options = CFDictionaryCreate(NULL,
        (const void **)&kSecImportExportPassphrase,
        (const void **)&password, 1,
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);
    ok_status(SecPKCS12Import(message, options, &items), "import user one");

    is(CFArrayGetCount(items), 1, "one identity");
    CFDictionaryRef item = CFArrayGetValueAtIndex(items, 0);
    SecIdentityRef identity = NULL;
    ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data");

    ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef");
    ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key");
    ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate");

    CFReleaseNull(items);
    CFReleaseNull(message);
    CFReleaseNull(options);
    CFReleaseNull(password);
    CFReleaseNull(cert);
    CFReleaseNull(pkey);

    message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
        _user_two_p12, sizeof(_user_two_p12), kCFAllocatorNull);
    items = NULL;
    password = CFSTR("user-two");
    options = CFDictionaryCreate(NULL,
        (const void **)&kSecImportExportPassphrase,
        (const void **)&password, 1,
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);

    ok_status(SecPKCS12Import(message, options, &items), "import user two");
    is(CFArrayGetCount(items), 1, "one identity");
    item = CFArrayGetValueAtIndex(items, 0);
    ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data");

    ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef");
    ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key");
    ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate");

    CFReleaseNull(items);
    CFReleaseNull(message);
    CFReleaseNull(options);
    CFReleaseNull(password);
    CFReleaseNull(cert);
    CFReleaseNull(pkey);



    message = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
                                          ECDSA_fails_import_p12, ECDSA_fails_import_p12_len, kCFAllocatorNull);
    items = NULL;
    password = CFSTR("test");
    options = CFDictionaryCreate(NULL,
                                 (const void **)&kSecImportExportPassphrase,
                                 (const void **)&password, 1,
                                 &kCFTypeDictionaryKeyCallBacks,
                                 &kCFTypeDictionaryValueCallBacks);

    ok_status(SecPKCS12Import(message, options, &items), "import ECDSA_fails_import_p12");
    is(CFArrayGetCount(items), 1, "one identity");
    item = CFArrayGetValueAtIndex(items, 0);
    ok(identity = (SecIdentityRef)CFDictionaryGetValue(item, kSecImportItemIdentity), "pull identity from imported data");

    ok(CFGetTypeID(identity)==SecIdentityGetTypeID(),"this is a SecIdentityRef");
    ok_status(SecIdentityCopyPrivateKey(identity, &pkey),"get private key");
    ok_status(SecIdentityCopyCertificate(identity, &cert), "get certificate");

    CFDataRef pubdata = NULL;
    SecKeyRef pubkey = NULL;

    ok_status(SecKeyCopyPublicBytes(pkey, &pubdata), "pub key from priv key");
    ok(pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
        CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes),
       "recreate seckey");

    /* Sign something. */
    uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, };
    size_t sigLen = SecKeyGetSize(pkey, kSecKeySignatureSize);
    uint8_t sig[sigLen];
    ok_status(SecKeyRawSign(pkey, kSecPaddingPKCS1,
                            something, sizeof(something), sig, &sigLen), "sign something");
    ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1,
                              something, sizeof(something), sig, sigLen), "verify sig on something");


    CFReleaseNull(pubdata);
    CFReleaseNull(pubkey);
    CFReleaseNull(pkey);

    ok(pkey = SecKeyCreateECPrivateKey(kCFAllocatorDefault,
        ECDSA_fails_import_priv_only, ECDSA_fails_import_priv_only_len,
        kSecKeyEncodingPkcs1), "import privkey without pub");
    ok_status(SecKeyCopyPublicBytes(pkey, &pubdata), "pub key from priv key");
    ok(pubkey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
        CFDataGetBytePtr(pubdata), CFDataGetLength(pubdata), kSecKeyEncodingBytes),
       "recreate seckey");
    ok_status(SecKeyRawVerify(pubkey, kSecPaddingPKCS1,
        something, sizeof(something), sig, sigLen), "verify sig on something");

    CFReleaseNull(pubdata);
    CFReleaseNull(pubkey);
    CFReleaseNull(pkey);
    CFReleaseNull(items);
    CFReleaseNull(message);
    CFReleaseNull(options);
    CFReleaseNull(password);
    CFReleaseNull(cert);

}
static OSStatus
parseIncomingCerts(CFArrayRef			certs,
                   SSLCertificate       **destCertChain, /* &ctx->{localCertChain,encryptCertChain} */
                   tls_private_key_t    *sslPrivKey)	 /* &ctx->signingPrivKeyRef, etc. */
{
    OSStatus			ortn;
    CFIndex				ix, numCerts;
    SecIdentityRef 		identity;
    SSLCertificate      *certChain = NULL;	/* Retained */
    SecCertificateRef	leafCert = NULL;	/* Retained */
    SecKeyRef           privKey = NULL;	/* Retained */

    assert(destCertChain != NULL);		/* though its referent may be NULL */
    assert(sslPrivKey != NULL);

    if (certs == NULL) {
        sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
        ortn = errSSLBadCert;
        goto errOut;
    }
    numCerts = CFArrayGetCount(certs);
    if (numCerts == 0) {
        sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
        ortn = errSSLBadCert;
        goto errOut;
    }

    certChain=sslMalloc(numCerts*sizeof(SSLCertificate));
    if (!certChain) {
        ortn = errSecAllocate;
        goto errOut;
    }

    /*
     * Certs[0] is an SecIdentityRef from which we extract subject cert,
     * privKey, pubKey.
     *
     * 1. ensure the first element is a SecIdentityRef.
     */
    identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
    if (identity == NULL) {
        sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
        ortn = errSecParam;
        goto errOut;
    }
    if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
        sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
        ortn = errSecParam;
        goto errOut;
    }

    /*
     * 2. Extract cert, keys and convert to local format.
     */
    ortn = SecIdentityCopyCertificate(identity, &leafCert);
    if (ortn) {
        sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
        goto errOut;
    }

    /* Fetch private key from identity */
    ortn = SecIdentityCopyPrivateKey(identity, &privKey);
    if (ortn) {
        sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
                    (int)ortn);
        goto errOut;
    }

    /* Convert the input array of SecIdentityRef at the start to an array of
     all certificates. */
    SSLCopyBufferFromData(SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert), &certChain[0].derCert);
    certChain[0].next = NULL;

    for (ix = 1; ix < numCerts; ++ix) {
        SecCertificateRef intermediate =
        (SecCertificateRef)CFArrayGetValueAtIndex(certs, ix);
        if (intermediate == NULL) {
            sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
            ortn = errSecParam;
            goto errOut;
        }
        if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
            sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
            ortn = errSecParam;
            goto errOut;
        }

        SSLCopyBufferFromData(SecCertificateGetBytePtr(intermediate), SecCertificateGetLength(intermediate), &certChain[ix].derCert);
        certChain[ix].next = NULL;
        certChain[ix-1].next = &certChain[ix];

    }

    size_t size = SecKeyGetBlockSize(privKey);
    tls_private_key_desc_t desc;

    if(SecKeyGetAlgorithmId(privKey) == kSecRSAAlgorithmID) {
        desc.type = tls_private_key_type_rsa;
        desc.rsa.sign = mySSLPrivKeyRSA_sign;
        desc.rsa.decrypt = mySSLPrivKeyRSA_decrypt;
        desc.rsa.size = SecKeyGetBlockSize(privKey);
    } else if (SecKeyGetAlgorithmId(privKey) == kSecECDSAAlgorithmID) {
        desc.type = tls_private_key_type_ecdsa;
        desc.ecdsa.sign = mySSLPrivKeyECDSA_sign;
        desc.ecdsa.curve = SecECKeyGetNamedCurve(privKey);
#if TARGET_OS_IPHONE
        /* Compute signature size from key size */
        desc.ecdsa.size  = 8+2*size;
#else
        desc.ecdsa.size  = size;
#endif
    } else {
        ortn = errSecParam;
        goto errOut;
    }
    *sslPrivKey = tls_private_key_create(&desc, privKey, (tls_private_key_ctx_release)&CFRelease);
    if(*sslPrivKey)
        ortn = errSecSuccess;
    else
        ortn = errSecAllocate;
    
    /* SUCCESS */
errOut:
    CFReleaseSafe(leafCert);

    if (ortn) {
        free(certChain);
        CFReleaseSafe(privKey);
        *destCertChain = NULL;
    } else {
        *destCertChain = certChain;
    }
    
    return ortn;
}