/* 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;
}
Exemple #3
0
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);
}
Exemple #4
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;
}
// 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;
}