/* * Get algorithm id for a SSLPrivKey object. */ CFIndex sslPrivKeyGetAlgorithmID(SSLPrivKey *privKey) { #if TARGET_OS_IOS return SecKeyGetAlgorithmID(SECKEYREF(privKey)); #else return SecKeyGetAlgorithmId(SECKEYREF(privKey)); #endif }
/* * Get algorithm id for a SSLPrivKey object. */ CFIndex sslPrivKeyGetAlgorithmID(SecKeyRef privKey) { #if TARGET_OS_IPHONE return SecKeyGetAlgorithmID(privKey); #else return SecKeyGetAlgorithmId(privKey); #endif }
SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) { CFDataRef serializedPublic = NULL; SecKeyRef result = NULL; require_noerr_quiet(SecKeyCopyPublicBytes(privateKey, &serializedPublic), fail); require_quiet(serializedPublic, fail); result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmID(privateKey), serializedPublic); fail: CFReleaseSafe(serializedPublic); return result; }
static CFStringRef SecECPrivateKeyCopyKeyDescription(SecKeyRef key) { //curve long curveType = (long)SecECKeyGetNamedCurve(key); char* curve= NULL; switch (curveType) { case 23: curve = "kSecECCurveSecp256r1"; break; case 24: curve = "kSecECCurveSecp384r1"; break; case 25: curve = "kSecECCurveSecp521r1"; break; case -1: curve = "kSecECCurveNone"; break; default: curve = "kSecECCurveNone"; break; } return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( "<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"), curve, (long)SecKeyGetAlgorithmID(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key); }
static CFStringRef SecECPublicKeyCopyKeyDescription(SecKeyRef key) { ccec_pub_ctx_t ecPubkey; CFStringRef keyDescription = NULL; size_t xlen, ylen, ix; CFMutableStringRef xString = NULL; CFMutableStringRef yString = NULL; ecPubkey.pub = key->key; //curve long curveType = (long)SecECKeyGetNamedCurve(key); char* curve= NULL; switch (curveType) { case 23: curve = "kSecECCurveSecp256r1"; break; case 24: curve = "kSecECCurveSecp384r1"; break; case 25: curve = "kSecECCurveSecp521r1"; break; case -1: curve = "kSecECCurveNone"; break; default: curve = "kSecECCurveNone"; break; } uint8_t *xunit = (uint8_t*)ccec_ctx_x(ecPubkey); require_quiet( NULL != xunit, fail); xlen = (size_t)strlen((char*)xunit); xString = CFStringCreateMutable(kCFAllocatorDefault, xlen * 2); require_quiet( NULL != xString, fail); for (ix = 0; ix < xlen; ++ix) { CFStringAppendFormat(xString, NULL, CFSTR("%02X"), xunit[ix]); } uint8_t *yunit = (uint8_t*)ccec_ctx_y(ecPubkey); require_quiet( NULL != yunit, fail); ylen = (size_t)strlen((char*)yunit); yString = CFStringCreateMutable(kCFAllocatorDefault, ylen*2); require_quiet( NULL != yString, fail); for(ix = 0; ix < ylen; ++ix) { CFStringAppendFormat(yString, NULL, CFSTR("%02X"), yunit[ix]); } keyDescription = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR( "<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, y: %@, x: %@, addr: %p>"), curve, (long)SecKeyGetAlgorithmID(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), yString, xString, key); fail: CFReleaseSafe(xString); CFReleaseSafe(yString); if(!keyDescription) keyDescription = CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef curve type: %s, algorithm id: %lu, key type: %s, version: %d, block size: %zu bits, addr: %p>"), curve,(long)SecKeyGetAlgorithmID(key), key->key_class->name, key->key_class->version, (8*SecKeyGetBlockSize(key)), key); return keyDescription; }
static SecCmsRecipientInfoRef nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelector type, SecCertificateRef cert, SecPublicKeyRef pubKey, const SecAsn1Item *subjKeyID) { SecCmsRecipientInfoRef ri; void *mark; SECOidTag certalgtag; OSStatus rv = SECSuccess; SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; unsigned long version; SecAsn1Item * dummy; PLArenaPool *poolp; const SECAlgorithmID *algid; SECAlgorithmID freeAlgID; SecCmsRecipientIdentifier *rid; poolp = envd->contentInfo.cmsg->poolp; mark = PORT_ArenaMark(poolp); ri = (SecCmsRecipientInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsRecipientInfo)); if (ri == NULL) goto loser; ri->envelopedData = envd; #if USE_CDSA_CRYPTO if (type == SecCmsRecipientIDIssuerSN) { rv = SecCertificateGetAlgorithmID(cert,&algid); } else { PORT_Assert(pubKey); rv = SecKeyGetAlgorithmID(pubKey,&algid); } #else ri->cert = CERT_DupCertificate(cert); if (ri->cert == NULL) goto loser; const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; #endif certalgtag = SECOID_GetAlgorithmTag(algid); rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; rid->identifierType = type; if (type == SecCmsRecipientIDIssuerSN) { rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (rid->id.issuerAndSN == NULL) { break; } } else if (type == SecCmsRecipientIDSubjectKeyID){ rid->id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item); if (rid->id.subjectKeyID == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); if (rid->id.subjectKeyID->Data == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } #if 0 SecCmsKeyTransRecipientInfoEx *riExtra; riExtra = &ri->ri.keyTransRecipientInfoEx; riExtra->version = 0; riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); if (riExtra->pubKey == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } #endif } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); if (type == SecCmsRecipientIDSubjectKeyID) { rv = SECFailure; break; } /* backward compatibility - this is not really a keytrans operation */ ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; /* hardcoded issuerSN choice for now */ ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = SecCmsRecipientIDIssuerSN; ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); if (type == SecCmsRecipientIDSubjectKeyID) { rv = SECFailure; break; } /* a key agreement op */ ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree; if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } /* we do not support the case where multiple recipients * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys * in this case, we would need to walk all the recipientInfos, take the * ones that do KeyAgreement algorithms and join them, algorithm by algorithm * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ /* only epheremal-static Diffie-Hellman is supported for now * this is the only form of key agreement that provides potential anonymity * of the sender, plus we do not have to include certs in the message */ /* force single recipientEncryptedKey for now */ if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) { rv = SECFailure; break; } /* hardcoded IssuerSN choice for now */ rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN; if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); /* see RFC2630 12.3.1.1 */ oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey; rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, (void *)rek); break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } if (rv == SECFailure) goto loser; /* set version */ switch (ri->recipientInfoType) { case SecCmsRecipientInfoIDKeyTrans: if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN) version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; else version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); if (dummy == NULL) goto loser; break; case SecCmsRecipientInfoIDKeyAgree: dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; case SecCmsRecipientInfoIDKEK: /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), SEC_CMS_KEK_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; } if (SecCmsEnvelopedDataAddRecipient(envd, ri)) goto loser; PORT_ArenaUnmark (poolp, mark); #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return ri; loser: #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif PORT_ArenaRelease (poolp, mark); return NULL; }
OSStatus SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, SECOidTag bulkalgtag) { SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; #if 0 SecAsn1Item * params = NULL; SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; #endif /* 0 */ const SECAlgorithmID *algid; PLArenaPool *poolp; SecCmsKeyTransRecipientInfoEx *extra = NULL; Boolean usesSubjKeyID; poolp = ri->envelopedData->contentInfo.cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { #if USE_CDSA_CRYPTO rv = SecCertificateGetAlgorithmID(cert,&algid); if (rv) return SECFailure; #else SECAlgorithmID freeAlgID; const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; #endif } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } #if USE_CDSA_CRYPTO rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); if (rv) #endif return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(algid); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; #if 0 case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, bulkalgtag, &ri->ri.keyTransRecipientInfo.encKey, ¶ms, ri->cmsg->pwfn_arg); if (rv != SECSuccess) break; /* here, we DO need to pass the params to the wrap function because, with * RSA, there is no funny stuff going on with generation of IV vectors or so */ rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; #endif /* 0 */ default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return rv; }
OSStatus SecCmsRecipientInfoWrapBulkKey(SecCmsRecipientInfoRef ri, SecSymmetricKeyRef bulkkey, SECOidTag bulkalgtag) { SecCertificateRef cert; SECOidTag certalgtag; OSStatus rv = SECSuccess; #if 0 CSSM_DATA_PTR params = NULL; #endif /* 0 */ SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; const SECAlgorithmID *algid; PLArenaPool *poolp; SecCmsKeyTransRecipientInfoEx *extra = NULL; Boolean usesSubjKeyID; uint8 nullData[2] = {SEC_ASN1_NULL, 0}; SECItem nullItem; SecCmsKeyAgreeRecipientInfo *kari; poolp = ri->cmsg->poolp; cert = ri->cert; usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); if (cert) { rv = SecCertificateGetAlgorithmID(cert,&algid); if (rv) return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else if (usesSubjKeyID) { extra = &ri->ri.keyTransRecipientInfoEx; /* sanity check */ PORT_Assert(extra->pubKey); if (!extra->pubKey) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } rv = SecKeyGetAlgorithmID(extra->pubKey,&algid); if (rv) return SECFailure; certalgtag = SECOID_GetAlgorithmTag(algid); } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX set ri->recipientInfoType to the proper value here */ /* or should we look if it's been set already ? */ certalgtag = SECOID_GetAlgorithmTag(algid); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: /* wrap the symkey */ if (cert) { rv = SecCmsUtilEncryptSymKeyRSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } else if (usesSubjKeyID) { PORT_Assert(extra != NULL); rv = SecCmsUtilEncryptSymKeyRSAPubKey(poolp, extra->pubKey, bulkkey, &ri->ri.keyTransRecipientInfo.encKey); if (rv != SECSuccess) break; } rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); break; #if 0 case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: rv = SecCmsUtilEncryptSymKeyMISSI(poolp, cert, bulkkey, bulkalgtag, &ri->ri.keyTransRecipientInfo.encKey, ¶ms, ri->cmsg->pwfn_arg); if (rv != SECSuccess) break; /* here, we DO need to pass the params to the wrap function because, with * RSA, there is no funny stuff going on with generation of IV vectors or so */ rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, params); break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* see RFC2630 12.3.1.1 */ if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = SecCmsUtilEncryptSymKeyESDH(poolp, cert, bulkkey, &rek->encKey, &ri->ri.keyAgreeRecipientInfo.ukm, &ri->ri.keyAgreeRecipientInfo.keyEncAlg, &oiok->id.originatorPublicKey.publicKey); break; #endif /* 0 */ case SEC_OID_EC_PUBLIC_KEY: /* These were set up in nss_cmsrecipientinfo_create() */ kari = &ri->ri.keyAgreeRecipientInfo; rek = kari->recipientEncryptedKeys[0]; if (rek == NULL) { rv = SECFailure; break; } oiok = &(kari->originatorIdentifierOrKey); PORT_Assert(oiok->identifierType == SecCmsOriginatorIDOrKeyOriginatorPublicKey); /* * RFC 3278 3.1.1 says this AlgId must contain NULL params which is contrary to * any other use of the SEC_OID_EC_PUBLIC_KEY OID. So we provide one * explicitly instead of mucking up the login in SECOID_SetAlgorithmID(). */ nullItem.Data = nullData; nullItem.Length = 2; if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, SEC_OID_EC_PUBLIC_KEY, &nullItem) != SECSuccess) { rv = SECFailure; break; } /* this will generate a key pair, compute the shared secret, */ /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ rv = SecCmsUtilEncryptSymKeyECDH(poolp, cert, bulkkey, &rek->encKey, &kari->ukm, &kari->keyEncAlg, &oiok->id.originatorPublicKey.publicKey); /* this is a BIT STRING */ oiok->id.originatorPublicKey.publicKey.Length <<= 3; break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return rv; }
/* Extract the pubkey from a cert chain, and send it to the tls_handshake context */ int tls_set_encrypt_pubkey(tls_handshake_t hdsk, const SSLCertificate *certchain) { int err; CFIndex algId; SecTrustRef trustRef = NULL; SecKeyRef pubkey = NULL; CFDataRef modulus = NULL; CFDataRef exponent = NULL; #if 0 { /* dump certs */ int i=0; int j; const SSLCertificate *tmp = certchain; while(tmp) { printf("cert%d[] = {", i); for(j=0; j<tmp->derCert.length; j++) { if((j&0xf)==0) printf("\n"); printf("0x%02x, ", tmp->derCert.data[j]); } printf("}\n"); tmp=tmp->next; i++; } } #endif require_noerr((err=tls_create_trust_from_certs(certchain, &trustRef)), errOut); require_action((pubkey = SecTrustCopyPublicKey(trustRef)), errOut, err=-9808); // errSSLBadCert #if TARGET_OS_IPHONE algId = SecKeyGetAlgorithmID(pubkey); #else algId = SecKeyGetAlgorithmId(pubkey); #endif err = -9809; //errSSLCrypto; switch(algId) { case kSecRSAAlgorithmID: { require((modulus = SecKeyCopyModulus(pubkey)), errOut); require((exponent = SecKeyCopyExponent(pubkey)), errOut); tls_buffer mod; tls_buffer exp; mod.data = (uint8_t *)CFDataGetBytePtr(modulus); mod.length = CFDataGetLength(modulus); exp.data = (uint8_t *)CFDataGetBytePtr(exponent); exp.length = CFDataGetLength(exponent); err = tls_handshake_set_encrypt_rsa_public_key(hdsk, &mod, &exp); break; } default: break; } errOut: CFReleaseSafe(trustRef); CFReleaseSafe(pubkey); CFReleaseSafe(modulus); CFReleaseSafe(exponent); return err; }
/* Extract the pubkey from a cert chain, and send it to the tls_handshake context */ static int tls_set_peer_pubkey(tls_handshake_t hdsk, const SSLCertificate *certchain) { int err; CFIndex algId; SecKeyRef pubkey = NULL; CFDataRef modulus = NULL; CFDataRef exponent = NULL; CFDataRef ecpubdata = NULL; #if 0 { /* dump certs */ int i=0; int j; const SSLCertificate *tmp = certchain; while(tmp) { printf("cert%d[] = {", i); for(j=0; j<tmp->derCert.length; j++) { if((j&0xf)==0) printf("\n"); printf("0x%02x, ", tmp->derCert.data[j]); } printf("}\n"); tmp=tmp->next; i++; } } #endif require_noerr((err=sslCopyPeerPubKey(certchain, &pubkey)), errOut); #if TARGET_OS_IPHONE algId = SecKeyGetAlgorithmID(pubkey); #else algId = SecKeyGetAlgorithmId(pubkey); #endif err = errSSLCrypto; switch(algId) { case kSecRSAAlgorithmID: { require((modulus = SecKeyCopyModulus(pubkey)), errOut); require((exponent = SecKeyCopyExponent(pubkey)), errOut); tls_buffer mod; tls_buffer exp; mod.data = (uint8_t *)CFDataGetBytePtr(modulus); mod.length = CFDataGetLength(modulus); exp.data = (uint8_t *)CFDataGetBytePtr(exponent); exp.length = CFDataGetLength(exponent); err = tls_handshake_set_peer_rsa_public_key(hdsk, &mod, &exp); break; } case kSecECDSAAlgorithmID: { tls_named_curve curve = SecECKeyGetNamedCurve(pubkey); require((ecpubdata = SecECKeyCopyPublicBits(pubkey)), errOut); tls_buffer pubdata; pubdata.data = (uint8_t *)CFDataGetBytePtr(ecpubdata); pubdata.length = CFDataGetLength(ecpubdata); err = tls_handshake_set_peer_ec_public_key(hdsk, curve, &pubdata); break; } default: break; } errOut: CFReleaseSafe(pubkey); CFReleaseSafe(modulus); CFReleaseSafe(exponent); CFReleaseSafe(ecpubdata); return err; }
/* * SecCmsSignerInfoSign - sign something * */ OSStatus SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType) { SecCertificateRef cert; SecPrivateKeyRef privkey = NULL; SECOidTag digestalgtag; SECOidTag pubkAlgTag; CSSM_DATA signature = { 0 }; OSStatus rv; PLArenaPool *poolp, *tmppoolp = NULL; const SECAlgorithmID *algID; SECAlgorithmID freeAlgID; //CERTSubjectPublicKeyInfo *spki; PORT_Assert (digest != NULL); poolp = signerinfo->cmsg->poolp; switch (signerinfo->signerIdentifier.identifierType) { case SecCmsSignerIDIssuerSN: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; cert = signerinfo->cert; if (SecCertificateGetAlgorithmID(cert,&algID)) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } break; case SecCmsSignerIDSubjectKeyID: privkey = signerinfo->signingKey; signerinfo->signingKey = NULL; #if 0 spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey); SECKEY_DestroyPublicKey(signerinfo->pubKey); signerinfo->pubKey = NULL; SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm); SECKEY_DestroySubjectPublicKeyInfo(spki); algID = &freeAlgID; #else #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)) if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) { #else /* TBD: Unify this code. Currently, iOS has an incompatible * SecKeyGetAlgorithmID implementation. */ if (true) { #endif PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } CFRelease(signerinfo->pubKey); signerinfo->pubKey = NULL; #endif break; default: PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE); goto loser; } digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo); /* * XXX I think there should be a cert-level interface for this, * so that I do not have to know about subjectPublicKeyInfo... */ pubkAlgTag = SECOID_GetAlgorithmTag(algID); if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) { SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE); } #if 0 // @@@ Not yet /* Fortezza MISSI have weird signature formats. * Map them to standard DSA formats */ pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag); #endif if (signerinfo->authAttr != NULL) { CSSM_DATA encoded_attrs; /* find and fill in the message digest attribute. */ rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE); if (rv != SECSuccess) goto loser; if (contentType != NULL) { /* if the caller wants us to, find and fill in the content type attribute. */ rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE); if (rv != SECSuccess) goto loser; } if ((tmppoolp = PORT_NewArena (1024)) == NULL) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } /* * Before encoding, reorder the attributes so that when they * are encoded, they will be conforming DER, which is required * to have a specific order and that is what must be used for * the hash/signature. We do this here, rather than building * it into EncodeAttributes, because we do not want to do * such reordering on incoming messages (which also uses * EncodeAttributes) or our old signatures (and other "broken" * implementations) will not verify. So, we want to guarantee * that we send out good DER encodings of attributes, but not * to expect to receive them. */ if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess) goto loser; encoded_attrs.Data = NULL; encoded_attrs.Length = 0; if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr), &encoded_attrs) == NULL) goto loser; rv = SEC_SignData(&signature, encoded_attrs.Data, (int)encoded_attrs.Length, privkey, digestalgtag, pubkAlgTag); PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */ tmppoolp = 0; } else { rv = SGN_Digest(privkey, digestalgtag, pubkAlgTag, &signature, digest); } SECKEY_DestroyPrivateKey(privkey); privkey = NULL; if (rv != SECSuccess) goto loser; if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) != SECSuccess) goto loser; SECITEM_FreeItem(&signature, PR_FALSE); if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) { /* * RFC 3278 section section 2.1.1 states that the signatureAlgorithm * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey * as would appear in other forms of signed datas. However Microsoft doesn't * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there, * MS can't verify - presumably because it takes the digest of the digest * before feeding it to ECDSA. * We handle this with a preference; default if it's not there is * "Microsoft compatibility mode". */ if(!SecCmsMsEcdsaCompatMode()) { pubkAlgTag = SEC_OID_ECDSA_WithSHA1; } /* else violating the spec for compatibility */ } if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, NULL) != SECSuccess) goto loser; return SECSuccess; loser: if (signature.Length != 0) SECITEM_FreeItem (&signature, PR_FALSE); if (privkey) SECKEY_DestroyPrivateKey(privkey); if (tmppoolp) PORT_FreeArena(tmppoolp, PR_FALSE); return SECFailure; } OSStatus SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray, CFTypeRef policies, SecTrustRef *trustRef) { SecCertificateRef cert; CFAbsoluteTime stime; OSStatus rv; CSSM_DATA_PTR *otherCerts; if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) { dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n"); signerinfo->verificationStatus = SecCmsVSSigningCertNotFound; return SECFailure; } /* * Get and convert the signing time; if available, it will be used * both on the cert verification and for importing the sender * email profile. */ CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies); if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo, timeStampPolicies, &stime) != SECSuccess) if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess) stime = CFAbsoluteTimeGetCurrent(); CFReleaseSafe(timeStampPolicies); rv = SecCmsSignedDataRawCerts(signerinfo->sigd, &otherCerts); if(rv) { return rv; } rv = CERT_VerifyCert(keychainOrArray, cert, otherCerts, policies, stime, trustRef); dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert)); if (rv || !trustRef) { if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT) { /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */ if (signerinfo->verificationStatus == SecCmsVSGoodSignature) signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted; } } /* FIXME isn't this leaking the cert? */ dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv); return rv; }