/* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef. */ SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) { SecKeyRef pubKey = NULL; SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0); (void) SecCertificateCopyPublicKey(certificate, &pubKey); return pubKey; }
/* * SecCmsUtilEncryptSymKeyRSA - wrap a symmetric key with RSA * * this function takes a symmetric key and encrypts it using an RSA public key * according to PKCS#1 and RFC2633 (S/MIME) */ OSStatus SecCmsUtilEncryptSymKeyRSA(PLArenaPool *poolp, SecCertificateRef cert, SecSymmetricKeyRef bulkkey, SecAsn1Item * encKey) { OSStatus rv; SecPublicKeyRef publickey; #if USE_CDSA_CRYPTO rv = SecCertificateCopyPublicKey(cert,&publickey); #else publickey = SecCertificateCopyPublicKey(cert); #endif if (publickey == NULL) return SECFailure; rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, publickey, bulkkey, encKey); CFRelease(publickey); return rv; }
extern "C" int32_t AppleCryptoNative_X509GetPublicKey(SecCertificateRef cert, SecKeyRef* pPublicKeyOut, int32_t* pOSStatusOut) { if (pPublicKeyOut != nullptr) *pPublicKeyOut = nullptr; if (pOSStatusOut != nullptr) *pOSStatusOut = noErr; if (cert == nullptr || pPublicKeyOut == nullptr || pOSStatusOut == nullptr) return kErrorBadInput; *pOSStatusOut = SecCertificateCopyPublicKey(cert, pPublicKeyOut); return (*pOSStatusOut == noErr); }
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; }
// Extract a public key object from a SubjectPublicKeyInfo SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert) { SecPublicKeyRef keyRef = NULL; SecCertificateCopyPublicKey(cert,&keyRef); return keyRef; }
CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData, CryptoX_PublicKey* aPublicKey) { if (!aCertData || !aPublicKey) { return CryptoX_Error; } *aPublicKey = NULL; if (!OnLionOrLater()) { if (!sCspHandle) { CSSM_RETURN rv; if (!sCssmInitialized) { CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE; rv = CSSM_Init(&sCssmVersion, CSSM_PRIVILEGE_SCOPE_PROCESS, &sMozCssmGuid, CSSM_KEY_HIERARCHY_NONE, &pvcPolicy, NULL); if (rv != CSSM_OK) { return CryptoX_Error; } sCssmInitialized = true; } rv = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL); if (rv != CSSM_OK) { return CryptoX_Error; } CSSM_CSP_HANDLE cspHandle; rv = CSSM_ModuleAttach(&gGuidAppleCSP, &sCssmVersion, &cssmMemFuncs, 0, CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &cspHandle); if (rv != CSSM_OK) { return CryptoX_Error; } sCspHandle = cspHandle; } FILE* certFile = NULL; long certFileSize = 0; uint8* certBuffer = NULL; certFile = fopen((char*)aCertData, "rb"); if (!certFile) { return CryptoX_Error; } if (fseek(certFile, 0, SEEK_END)) { fclose(certFile); return CryptoX_Error; } certFileSize = ftell(certFile); if (certFileSize < 0) { fclose(certFile); return CryptoX_Error; } certBuffer = (uint8*)malloc(certFileSize); if (fseek(certFile, 0, SEEK_SET)) { free(certBuffer); fclose(certFile); return CryptoX_Error; } uint readResult = fread(certBuffer, sizeof(uint8), certFileSize, certFile); if (readResult != certFileSize) { free(certBuffer); fclose(certFile); return CryptoX_Error; } fclose(certFile); CFDataRef certData = CFDataCreate(kCFAllocatorDefault, certBuffer, certFileSize); free(certBuffer); if (!certData) { return CryptoX_Error; } SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData); CFRelease(certData); if (!cert) { return CryptoX_Error; } SecKeyRef publicKey; OSStatus status = SecCertificateCopyPublicKey(cert, (SecKeyRef*)&publicKey); CFRelease(cert); if (status) { return CryptoX_Error; } *aPublicKey = (void*)publicKey; return CryptoX_Success; } CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, aCertData, strlen((char*)aCertData), false); if (!url) { return CryptoX_Error; } CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url); if (!stream) { CFRelease(url); return CryptoX_Error; } SecTransformRef readTransform = SecTransformCreateReadTransformWithReadStreamPtr(stream); if (!readTransform) { CFRelease(url); CFRelease(stream); return CryptoX_Error; } CFErrorRef error; CFDataRef tempCertData = (CFDataRef)SecTransformExecutePtr(readTransform, &error); if (!tempCertData || error) { CFRelease(url); CFRelease(stream); CFRelease(readTransform); return CryptoX_Error; } SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, tempCertData); if (!cert) { CFRelease(url); CFRelease(stream); CFRelease(readTransform); CFRelease(tempCertData); return CryptoX_Error; } CryptoX_Result result = CryptoX_Error; OSStatus status = SecCertificateCopyPublicKey(cert, (SecKeyRef*)aPublicKey); if (status == 0) { result = CryptoX_Success; } CFRelease(url); CFRelease(stream); CFRelease(readTransform); CFRelease(tempCertData); CFRelease(cert); return result; }
OSStatus SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType) { SecPublicKeyRef publickey = NULL; SecCmsAttribute *attr; CSSM_DATA encoded_attrs; SecCertificateRef cert; SecCmsVerificationStatus vs = SecCmsVSUnverified; PLArenaPool *poolp; SECOidTag digestAlgTag, digestEncAlgTag; if (signerinfo == NULL) return SECFailure; /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */ /* cert has not been verified */ if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, NULL)) == NULL) { dprintf("SecCmsSignerInfoVerify: no signing cert\n"); vs = SecCmsVSSigningCertNotFound; goto loser; } dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); debugShowSigningCertificate(signerinfo); OSStatus status; if ((status = SecCertificateCopyPublicKey(cert, &publickey))) { syslog(LOG_ERR, "SecCmsSignerInfoVerifyWithPolicy: copy public key failed %d", (int)status); vs = SecCmsVSProcessingError; goto loser; } digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg)); digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg)); /* * Gross hack necessitated by RFC 3278 section 2.1.1, which states * that the signature algorithm (here, digestEncAlg) contains ecdsa_with-SHA1, * *not* (as in all other algorithms) the raw signature algorithm, e.g. * pkcs1RSAEncryption. */ if(digestEncAlgTag == SEC_OID_ECDSA_WithSHA1) { digestEncAlgTag = SEC_OID_EC_PUBLIC_KEY; } if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) { if (contentType) { /* * Check content type * * RFC2630 sez that if there are any authenticated attributes, * then there must be one for content type which matches the * content type of the content being signed, and there must * be one for message digest which matches our message digest. * So check these things first. */ if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL) { vs = SecCmsVSMalformedSignature; goto loser; } if (SecCmsAttributeCompareValue(attr, contentType) == PR_FALSE) { vs = SecCmsVSMalformedSignature; goto loser; } } /* * Check digest */ if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL) { vs = SecCmsVSMalformedSignature; goto loser; } if (SecCmsAttributeCompareValue(attr, digest) == PR_FALSE) { vs = SecCmsVSDigestMismatch; goto loser; } if ((poolp = PORT_NewArena (1024)) == NULL) { vs = SecCmsVSProcessingError; goto loser; } /* * Check signature * * The signature is based on a digest of the DER-encoded authenticated * attributes. So, first we encode and then we digest/verify. * we trust the decoder to have the attributes in the right (sorted) order */ encoded_attrs.Data = NULL; encoded_attrs.Length = 0; if (SecCmsAttributeArrayEncode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL || encoded_attrs.Data == NULL || encoded_attrs.Length == 0) { vs = SecCmsVSProcessingError; goto loser; } vs = (VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length, publickey, &(signerinfo->encDigest), digestAlgTag, digestEncAlgTag, signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature; dprintf("VFY_VerifyData (authenticated attributes): %s\n", (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature"); PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */ } else { CSSM_DATA_PTR sig; /* No authenticated attributes. The signature is based on the plain message digest. */ sig = &(signerinfo->encDigest); if (sig->Length == 0) goto loser; vs = (VFY_VerifyDigest(digest, publickey, sig, digestAlgTag, digestEncAlgTag, signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature; dprintf("VFY_VerifyData (plain message digest): %s\n", (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature"); } if (!SecCmsArrayIsEmpty((void **)signerinfo->unAuthAttr)) { dprintf("found an unAuthAttr\n"); OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy); dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux); if (rux) { goto loser; } } if (vs == SecCmsVSBadSignature) { /* * XXX Change the generic error into our specific one, because * in that case we get a better explanation out of the Security * Advisor. This is really a bug in our error strings (the * "generic" error has a lousy/wrong message associated with it * which assumes the signature verification was done for the * purposes of checking the issuer signature on a certificate) * but this is at least an easy workaround and/or in the * Security Advisor, which specifically checks for the error * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation * in that case but does not similarly check for * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would * probably say the wrong thing in the case that it *was* the * certificate signature check that failed during the cert * verification done above. Our error handling is really a mess. */ if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); } if (publickey != NULL) CFRelease(publickey); signerinfo->verificationStatus = vs; dprintfRC("SecCmsSignerInfoVerify end: cerp %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); dprintf("verificationStatus: %d\n", vs); return (vs == SecCmsVSGoodSignature) ? SECSuccess : SECFailure; loser: if (publickey != NULL) SECKEY_DestroyPublicKey (publickey); dprintf("verificationStatus2: %d\n", vs); signerinfo->verificationStatus = vs; PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); return SECFailure; }