diff options
author | wyllys <none@none> | 2007-03-03 05:56:22 -0800 |
---|---|---|
committer | wyllys <none@none> | 2007-03-03 05:56:22 -0800 |
commit | 02744e811b15322c5f109827a116c33bfe3438b5 (patch) | |
tree | b148880f0bcec1897d728c7e93c81233cd394131 /usr | |
parent | 3779d2d24dac3a9a84c5eefdeee36f7559299b2c (diff) | |
download | illumos-gate-02744e811b15322c5f109827a116c33bfe3438b5.tar.gz |
6523959 KMF needs keystore specific Verify operations
--HG--
rename : usr/src/lib/libkmf/include/oidsalg.h => deleted_files/usr/src/lib/libkmf/include/oidsalg.h
Diffstat (limited to 'usr')
-rw-r--r-- | usr/src/lib/libkmf/include/kmfapi.h | 5 | ||||
-rw-r--r-- | usr/src/lib/libkmf/include/kmfapiP.h | 33 | ||||
-rw-r--r-- | usr/src/lib/libkmf/include/kmftypes.h | 47 | ||||
-rw-r--r-- | usr/src/lib/libkmf/include/oidsalg.h | 52 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/algoid.c | 19 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/certop.c | 201 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/generalop.c | 47 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/kmfoids.c | 25 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/mapfile-vers | 12 | ||||
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/pk11keys.c | 2 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c | 2 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c | 491 | ||||
-rw-r--r-- | usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c | 179 |
13 files changed, 867 insertions, 248 deletions
diff --git a/usr/src/lib/libkmf/include/kmfapi.h b/usr/src/lib/libkmf/include/kmfapi.h index c7506ab9e6..fd29b0733c 100644 --- a/usr/src/lib/libkmf/include/kmfapi.h +++ b/usr/src/lib/libkmf/include/kmfapi.h @@ -85,6 +85,8 @@ extern KMF_RETURN KMF_FindCert(KMF_HANDLE_T, KMF_FINDCERT_PARAMS *, extern KMF_RETURN KMF_EncodeCertRecord(KMF_X509_CERTIFICATE *, KMF_DATA *); +extern KMF_RETURN KMF_DecodeCertData(KMF_DATA *, KMF_X509_CERTIFICATE **); + extern KMF_RETURN KMF_SignCertWithKey(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *); extern KMF_RETURN KMF_SignCertWithCert(KMF_HANDLE_T, @@ -98,7 +100,8 @@ extern KMF_RETURN KMF_VerifyCertWithKey(KMF_HANDLE_T, KMF_KEY_HANDLE *, const KMF_DATA *); extern KMF_RETURN KMF_VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *); -extern KMF_RETURN KMF_VerifyDataWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, +extern KMF_RETURN KMF_VerifyDataWithCert(KMF_HANDLE_T, + KMF_KEYSTORE_TYPE, KMF_ALGORITHM_INDEX, KMF_DATA *, KMF_DATA *, const KMF_DATA *); extern KMF_RETURN KMF_EncryptWithCert(KMF_HANDLE_T, KMF_DATA *, diff --git a/usr/src/lib/libkmf/include/kmfapiP.h b/usr/src/lib/libkmf/include/kmfapiP.h index 64b524b6a7..e20df89348 100644 --- a/usr/src/lib/libkmf/include/kmfapiP.h +++ b/usr/src/lib/libkmf/include/kmfapiP.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _KMFAPIP_H @@ -162,6 +162,13 @@ typedef struct { KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *); + KMF_RETURN (*VerifyDataWithCert) ( + KMF_HANDLE_T, + KMF_ALGORITHM_INDEX, + KMF_DATA *, + KMF_DATA *, + KMF_DATA *); + void (*Finalize) (); } KMF_PLUGIN_FUNCLIST; @@ -218,29 +225,10 @@ typedef struct _kmf_handle { KMF_PLUGIN_FUNCLIST *KMF_Plugin_Initialize(); KMF_RETURN -SignCert(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *); - -KMF_RETURN -VerifyCertWithKey(KMF_HANDLE_T, KMF_DATA *, const KMF_DATA *); - -KMF_RETURN -VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *); - -KMF_RETURN -VerifyDataWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, const KMF_DATA *); - -KMF_RETURN VerifyDataWithKey(KMF_HANDLE_T, KMF_DATA *, KMF_ALGORITHM_INDEX, KMF_DATA *, KMF_DATA *); KMF_RETURN -EncryptWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_DATA *, KMF_DATA *); - -KMF_RETURN -DecryptWithCert(KMF_HANDLE_T, KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *, - KMF_DATA *); - -KMF_RETURN SignCsr(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, KMF_X509_ALGORITHM_IDENTIFIER *, KMF_DATA *); @@ -265,8 +253,11 @@ KMF_PLUGIN *FindPlugin(KMF_HANDLE_T, KMF_KEYSTORE_TYPE); KMF_BOOL IsEqualOid(KMF_OID *, KMF_OID *); KMF_OID *X509_AlgIdToAlgorithmOid(KMF_ALGORITHM_INDEX); - KMF_ALGORITHM_INDEX X509_AlgorithmOidToAlgId(KMF_OID *); +KMF_RETURN PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, + const KMF_X509_SPKI *, CK_KEY_TYPE, CK_OBJECT_HANDLE *, + KMF_BOOL *); + KMF_RETURN GetIDFromSPKI(KMF_X509_SPKI *, KMF_DATA *); CK_RV DigestData(CK_SESSION_HANDLE, KMF_DATA *, KMF_DATA *); diff --git a/usr/src/lib/libkmf/include/kmftypes.h b/usr/src/lib/libkmf/include/kmftypes.h index c2e954c981..dc4a1f2b33 100644 --- a/usr/src/lib/libkmf/include/kmftypes.h +++ b/usr/src/lib/libkmf/include/kmftypes.h @@ -106,6 +106,22 @@ typedef enum { KMF_KU_ENCRYPT_DATA = 2 } KMF_KU_PURPOSE; +/* + * Algorithms + * This type defines a set of constants used to identify cryptographic + * algorithms. + */ +typedef enum { + KMF_ALGID_NONE = 0, + KMF_ALGID_CUSTOM, + KMF_ALGID_SHA1, + KMF_ALGID_RSA, + KMF_ALGID_DSA, + KMF_ALGID_MD5WithRSA, + KMF_ALGID_MD2WithRSA, + KMF_ALGID_SHA1WithRSA, + KMF_ALGID_SHA1WithDSA +} KMF_ALGORITHM_INDEX; /* Keystore Configuration */ typedef struct { @@ -204,6 +220,7 @@ typedef struct { typedef struct { KMF_KEYSTORE_TYPE kstype; KMF_DATA *certificate; + KMF_BIGINT *serial; KMF_DATA *ocsp_response; union { @@ -353,6 +370,7 @@ typedef struct { KMF_CREDENTIAL cred; KMF_ENCODE_FORMAT format; /* for key */ char *certLabel; + KMF_ALGORITHM_INDEX algid; union { KMF_NSS_PARAMS nss_opts; KMF_OPENSSL_PARAMS openssl_opts; @@ -625,23 +643,6 @@ typedef enum { KMF_ALGCLASS_DERIVEKEY } KMF_ALGCLASS; -/* - * Algorithms - * This type defines a set of constants used to identify cryptographic - * algorithms. - */ -typedef enum { - KMF_ALGID_NONE = 0, - KMF_ALGID_CUSTOM, - KMF_ALGID_SHA1, - KMF_ALGID_RSA, - KMF_ALGID_DSA, - KMF_ALGID_MD5WithRSA, - KMF_ALGID_MD2WithRSA, - KMF_ALGID_SHA1WithRSA, - KMF_ALGID_SHA1WithDSA -} KMF_ALGORITHM_INDEX; - typedef enum { KMF_CERT_ISSUER = 1, KMF_CERT_SUBJECT, @@ -1303,7 +1304,17 @@ KMFOID_PKIX_KP_IPSecEndSystem, KMFOID_PKIX_KP_IPSecTunnel, KMFOID_PKIX_KP_IPSecUser, KMFOID_PKIX_KP_TimeStamping, -KMFOID_PKIX_KP_OCSPSigning; +KMFOID_PKIX_KP_OCSPSigning, +KMFOID_SHA1, +KMFOID_RSA, +KMFOID_DSA, +KMFOID_MD5WithRSA, +KMFOID_MD2WithRSA, +KMFOID_SHA1WithRSA, +KMFOID_SHA1WithDSA, +KMFOID_OIW_DSAWithSHA1, +KMFOID_X9CM_DSA, +KMFOID_X9CM_DSAWithSHA1; /* * KMF Certificate validation codes. These may be masked together. diff --git a/usr/src/lib/libkmf/include/oidsalg.h b/usr/src/lib/libkmf/include/oidsalg.h deleted file mode 100644 index b0283f2ece..0000000000 --- a/usr/src/lib/libkmf/include/oidsalg.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* - * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. - * - */ - -#ifndef _OIDSALG_H -#define _OIDSALG_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <kmftypes.h> - -#ifdef __cplusplus -extern "C" { -#endif - -uint8_t - OID_OIW_SHA1[] = { OID_OIW_ALGORITHM, 26}, - OID_OIW_DSA[] = { OID_OIW_ALGORITHM, 12 }, - OID_OIW_DSAWithSHA1[] = { OID_OIW_ALGORITHM, 27 }, - OID_RSAEncryption[] = { OID_PKCS_1, 1 }, - OID_MD2WithRSA[] = { OID_PKCS_1, 2 }, - OID_MD5WithRSA[] = { OID_PKCS_1, 4 }, - OID_SHA1WithRSA[] = { OID_PKCS_1, 5 }, - OID_X9CM_DSA[] = { OID_X9CM_X9ALGORITHM, 1 }, - OID_X9CM_DSAWithSHA1[] = { OID_X9CM_X9ALGORITHM, 3} -; - -KMF_OID - KMFOID_SHA1 = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_SHA1}, - KMFOID_RSA = {OID_PKCS_1_LENGTH+1, OID_RSAEncryption}, - KMFOID_DSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSA}, - KMFOID_MD5WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD5WithRSA}, - KMFOID_MD2WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD2WithRSA}, - KMFOID_SHA1WithRSA = {OID_PKCS_1_LENGTH+1, OID_SHA1WithRSA}, - KMFOID_SHA1WithDSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSAWithSHA1}, - KMFOID_OIW_DSAWithSHA1 = {OID_OIW_ALGORITHM_LENGTH+1, - OID_OIW_DSAWithSHA1}, - KMFOID_X9CM_DSA = {OID_X9CM_X9ALGORITHM_LENGTH+1, OID_X9CM_DSA}, - KMFOID_X9CM_DSAWithSHA1 = {OID_X9CM_X9ALGORITHM_LENGTH+1, - OID_X9CM_DSAWithSHA1} - -; - -#ifdef __cplusplus -} -#endif -#endif /* _OIDSALG_H */ diff --git a/usr/src/lib/libkmf/libkmf/common/algoid.c b/usr/src/lib/libkmf/libkmf/common/algoid.c index 536e020474..d78541d1f0 100644 --- a/usr/src/lib/libkmf/libkmf/common/algoid.c +++ b/usr/src/lib/libkmf/libkmf/common/algoid.c @@ -12,7 +12,6 @@ #include <string.h> #include <kmfapiP.h> -#include <oidsalg.h> typedef struct { KMF_OID * AlgOID; @@ -23,15 +22,15 @@ typedef struct { * The following table defines the mapping of AlgOID's to AlgID's. */ static KMF_OID_ID ALGOID_ID_Table[] = { - {&KMFOID_X9CM_DSA, KMF_ALGID_DSA}, - {&KMFOID_X9CM_DSAWithSHA1, KMF_ALGID_SHA1WithDSA}, - {&KMFOID_SHA1, KMF_ALGID_SHA1}, - {&KMFOID_RSA, KMF_ALGID_RSA}, - {&KMFOID_DSA, KMF_ALGID_DSA}, - {&KMFOID_MD5WithRSA, KMF_ALGID_MD5WithRSA}, - {&KMFOID_MD2WithRSA, KMF_ALGID_MD2WithRSA}, - {&KMFOID_SHA1WithRSA, KMF_ALGID_SHA1WithRSA}, - {&KMFOID_SHA1WithDSA, KMF_ALGID_SHA1WithDSA} + {(KMF_OID *)&KMFOID_X9CM_DSA, KMF_ALGID_DSA}, + {(KMF_OID *)&KMFOID_X9CM_DSAWithSHA1, KMF_ALGID_SHA1WithDSA}, + {(KMF_OID *)&KMFOID_SHA1, KMF_ALGID_SHA1}, + {(KMF_OID *)&KMFOID_RSA, KMF_ALGID_RSA}, + {(KMF_OID *)&KMFOID_DSA, KMF_ALGID_DSA}, + {(KMF_OID *)&KMFOID_MD5WithRSA, KMF_ALGID_MD5WithRSA}, + {(KMF_OID *)&KMFOID_MD2WithRSA, KMF_ALGID_MD2WithRSA}, + {(KMF_OID *)&KMFOID_SHA1WithRSA, KMF_ALGID_SHA1WithRSA}, + {(KMF_OID *)&KMFOID_SHA1WithDSA, KMF_ALGID_SHA1WithDSA} }; #define NUM_ALGOIDS ((sizeof (ALGOID_ID_Table))/(sizeof (ALGOID_ID_Table[0]))) diff --git a/usr/src/lib/libkmf/libkmf/common/certop.c b/usr/src/lib/libkmf/libkmf/common/certop.c index 16d17bfa16..508293785f 100644 --- a/usr/src/lib/libkmf/libkmf/common/certop.c +++ b/usr/src/lib/libkmf/libkmf/common/certop.c @@ -44,6 +44,15 @@ #define X509_FORMAT_VERSION 2 static KMF_RETURN +SignCert(KMF_HANDLE_T, const KMF_DATA *, KMF_KEY_HANDLE *, KMF_DATA *); + +static KMF_RETURN +VerifyCertWithKey(KMF_HANDLE_T, KMF_DATA *, const KMF_DATA *); + +static KMF_RETURN +VerifyCertWithCert(KMF_HANDLE_T, const KMF_DATA *, const KMF_DATA *); + +static KMF_RETURN get_keyalg_from_cert(KMF_DATA *cert, KMF_KEY_ALG *keyalg) { KMF_RETURN rv; @@ -273,6 +282,20 @@ KMF_EncodeCertRecord(KMF_X509_CERTIFICATE *CertData, KMF_DATA *encodedCert) return (ret); } +KMF_RETURN +KMF_DecodeCertData(KMF_DATA *rawcert, KMF_X509_CERTIFICATE **certrec) +{ + KMF_RETURN ret = KMF_OK; + + if (rawcert == NULL || rawcert->Data == NULL || + rawcert->Length == 0 || certrec == NULL) + return (KMF_ERR_BAD_PARAMETER); + + ret = DerDecodeSignedCertificate(rawcert, certrec); + + return (ret); +} + /* * * Name: KMF_SignCertWithKey @@ -449,8 +472,15 @@ KMF_SignDataWithCert(KMF_HANDLE_T handle, plugin = FindPlugin(handle, Signkey.kstype); if (plugin != NULL && plugin->funclist->SignData != NULL) { + KMF_OID *oid; + + if (params->algid != KMF_ALGID_NONE) + oid = X509_AlgIdToAlgorithmOid(params->algid); + else + oid = CERT_ALG_OID(SignerCert); + ret = plugin->funclist->SignData(handle, &Signkey, - CERT_ALG_OID(SignerCert), tobesigned, output); + oid, tobesigned, output); if (ret != KMF_OK) goto cleanup; @@ -612,11 +642,14 @@ KMF_VerifyCertWithCert(KMF_HANDLE_T handle, */ KMF_RETURN KMF_VerifyDataWithCert(KMF_HANDLE_T handle, + KMF_KEYSTORE_TYPE kstype, + KMF_ALGORITHM_INDEX algid, KMF_DATA *indata, KMF_DATA *insig, const KMF_DATA *SignerCert) { KMF_RETURN ret; + KMF_PLUGIN *plugin; CLEAR_ERROR(handle, ret); if (ret != KMF_OK) @@ -631,7 +664,27 @@ KMF_VerifyDataWithCert(KMF_HANDLE_T handle, if (ret != KMF_OK) return (ret); - return (VerifyDataWithCert(handle, indata, insig, SignerCert)); + /* + * If NSS, use PKCS#11, we are not accessing the database(s), + * we just prefer the "verify" operation from the crypto framework. + * The OpenSSL version is unique in order to avoid a dependency loop + * with the kcfd(1M) process. + */ + if (kstype == KMF_KEYSTORE_NSS) + kstype = KMF_KEYSTORE_PK11TOKEN; + + plugin = FindPlugin(handle, kstype); + if (plugin == NULL) + return (KMF_ERR_PLUGIN_NOTFOUND); + + if (plugin->funclist->VerifyDataWithCert == NULL) + return (KMF_ERR_FUNCTION_NOT_FOUND); + + CLEAR_ERROR(handle, ret); + ret = (plugin->funclist->VerifyDataWithCert(handle, + algid, indata, insig, (KMF_DATA *)SignerCert)); + + return (ret); } /* @@ -663,6 +716,10 @@ KMF_EncryptWithCert(KMF_HANDLE_T handle, KMF_DATA *ciphertext) { KMF_RETURN ret; + KMF_X509_CERTIFICATE *x509cert = NULL; + KMF_X509_SPKI *pubkey; + KMF_OID *alg; + KMF_ALGORITHM_INDEX algid; CLEAR_ERROR(handle, ret); if (ret != KMF_OK) @@ -677,7 +734,31 @@ KMF_EncryptWithCert(KMF_HANDLE_T handle, if (ret != KMF_OK) return (ret); - return (EncryptWithCert(handle, cert, plaintext, ciphertext)); + /* Decode the cert so we can get the SPKI data */ + if ((ret = DerDecodeSignedCertificate(cert, &x509cert)) != KMF_OK) + return (ret); + + /* Get the public key info from the certificate */ + pubkey = &x509cert->certificate.subjectPublicKeyInfo; + + /* Use the algorithm in SPKI to encrypt data */ + alg = &pubkey->algorithm.algorithm; + + algid = X509_AlgorithmOidToAlgId(alg); + + /* DSA does not support encrypt */ + if (algid == KMF_ALGID_DSA || algid == KMF_ALGID_NONE) { + KMF_FreeSignedCert(x509cert); + free(x509cert); + return (KMF_ERR_BAD_ALGORITHM); + } + + ret = PKCS_EncryptData(handle, algid, pubkey, plaintext, ciphertext); + + KMF_FreeSignedCert(x509cert); + free(x509cert); + + return (ret); } /* @@ -1775,8 +1856,6 @@ KMF_ValidateCert(KMF_HANDLE_T handle, goto out; } - - (void) memset(&user_issuerDN, 0, sizeof (user_issuerDN)); if ((ret = KMF_DNParser(user_issuer, &user_issuerDN)) != KMF_OK) { *result |= KMF_CERT_VALIDATE_ERR_USER; goto out; @@ -1808,7 +1887,7 @@ KMF_ValidateCert(KMF_HANDLE_T handle, KMF_FreeDN(&user_subjectDN); /* - * Check KeyUsage extension. + * Check KeyUsage extension of the subscriber's certificate */ ret = cert_ku_check(handle, pcert); if (ret != KMF_OK) { @@ -1817,7 +1896,7 @@ KMF_ValidateCert(KMF_HANDLE_T handle, } /* - * Validate Extended KeyUsage extension. + * Validate Extended KeyUsage extension */ ret = cert_eku_check(handle, pcert); if (ret != KMF_OK) { @@ -1826,7 +1905,7 @@ KMF_ValidateCert(KMF_HANDLE_T handle, } /* - * Check the certificate's validity period. + * Check the certificate's validity period * * This step is needed when "ignore_date" in policy is set * to false. @@ -1861,11 +1940,10 @@ KMF_ValidateCert(KMF_HANDLE_T handle, * TA certificate. */ if (self_signed) { - ret = KMF_VerifyCertWithCert(handle, - pcert, pcert); + ret = KMF_VerifyCertWithCert(handle, pcert, pcert); } else { ret = kmf_find_ta_cert(handle, params, &ta_cert, - &user_issuerDN); + &user_issuerDN); if (ret != KMF_OK) { *result |= KMF_CERT_VALIDATE_ERR_TA; goto out; @@ -1873,7 +1951,6 @@ KMF_ValidateCert(KMF_HANDLE_T handle, ret = KMF_VerifyCertWithCert(handle, pcert, &ta_cert); } - if (ret != KMF_OK) { *result |= KMF_CERT_VALIDATE_ERR_SIGNATURE; goto out; @@ -1924,7 +2001,6 @@ check_revocation: goto out; } } - out: if (user_issuer) { KMF_FreeDN(&user_issuerDN); @@ -2327,7 +2403,7 @@ copy_algoid(KMF_X509_ALGORITHM_IDENTIFIER *destid, return (ret); } -KMF_RETURN +static KMF_RETURN SignCert(KMF_HANDLE_T handle, const KMF_DATA *SubjectCert, KMF_KEY_HANDLE *Signkey, @@ -2436,7 +2512,7 @@ cleanup: return (ret); } -KMF_RETURN +static KMF_RETURN VerifyCertWithKey(KMF_HANDLE_T handle, KMF_DATA *derkey, const KMF_DATA *CertToBeVerified) @@ -2509,6 +2585,9 @@ cleanup: return (ret); } +/* + * The key must be an ASN.1/DER encoded PKCS#1 key. + */ KMF_RETURN VerifyDataWithKey(KMF_HANDLE_T handle, KMF_DATA *derkey, @@ -2535,7 +2614,7 @@ cleanup: return (ret); } -KMF_RETURN +static KMF_RETURN VerifyCertWithCert(KMF_HANDLE_T handle, const KMF_DATA *CertToBeVerifiedData, const KMF_DATA *SignerCertData) @@ -2623,58 +2702,6 @@ cleanup: } KMF_RETURN -VerifyDataWithCert(KMF_HANDLE_T handle, - KMF_DATA *indata, - KMF_DATA *insig, - const KMF_DATA *SignerCertData) -{ - KMF_RETURN ret = KMF_OK; - KMF_X509_CERTIFICATE *SignerCert = NULL; - KMF_X509_SPKI *pubkey; - KMF_ALGORITHM_INDEX algid; - - if (!indata || - !indata->Data || - !indata->Length) - return (KMF_ERR_BAD_PARAMETER); - - if (!insig || - !insig->Data || - !insig->Length) - return (KMF_ERR_BAD_PARAMETER); - - - if (!SignerCertData || - !SignerCertData->Data || - !SignerCertData->Length) - return (KMF_ERR_BAD_PARAMETER); - - /* Decode the signer cert so we can get the SPKI data */ - ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert); - if (ret != KMF_OK) - goto cleanup; - - /* Get the public key info from the signer certificate */ - pubkey = &SignerCert->certificate.subjectPublicKeyInfo; - - algid = X509_AlgorithmOidToAlgId(CERT_ALG_OID(SignerCert)); - if (algid == KMF_ALGID_NONE) { - ret = KMF_ERR_BAD_ALGORITHM; - } else { - ret = PKCS_VerifyData(handle, algid, - pubkey, indata, insig); - } - -cleanup: - if (SignerCert) { - KMF_FreeSignedCert(SignerCert); - free(SignerCert); - } - - return (ret); -} - -KMF_RETURN SignCsr(KMF_HANDLE_T handle, const KMF_DATA *SubjectCsr, KMF_KEY_HANDLE *Signkey, @@ -2749,41 +2776,3 @@ cleanup: return (ret); } - -KMF_RETURN -EncryptWithCert(KMF_HANDLE_T handle, - KMF_DATA *cert, - KMF_DATA *plaintext, - KMF_DATA *ciphertext) -{ - KMF_RETURN ret = KMF_OK; - KMF_X509_CERTIFICATE *x509cert = NULL; - KMF_X509_SPKI *pubkey; - KMF_OID *alg; - KMF_ALGORITHM_INDEX algid; - - /* Decode the cert so we can get the SPKI data */ - if ((ret = DerDecodeSignedCertificate(cert, &x509cert)) != KMF_OK) - return (ret); - - /* Get the public key info from the certificate */ - pubkey = &x509cert->certificate.subjectPublicKeyInfo; - - /* Use the algorithm in SPKI to encrypt data */ - alg = &pubkey->algorithm.algorithm; - - algid = X509_AlgorithmOidToAlgId(alg); - - /* DSA does not support encrypt */ - if (algid == KMF_ALGID_DSA || algid == KMF_ALGID_NONE) { - KMF_FreeSignedCert(x509cert); - free(x509cert); - return (KMF_ERR_BAD_ALGORITHM); - } - - ret = PKCS_EncryptData(handle, algid, pubkey, plaintext, ciphertext); - KMF_FreeSignedCert(x509cert); - free(x509cert); - - return (ret); -} diff --git a/usr/src/lib/libkmf/libkmf/common/generalop.c b/usr/src/lib/libkmf/libkmf/common/generalop.c index ad596856b1..a9bf418ed3 100644 --- a/usr/src/lib/libkmf/libkmf/common/generalop.c +++ b/usr/src/lib/libkmf/libkmf/common/generalop.c @@ -687,6 +687,34 @@ KMF_OID2String(KMF_OID *oid) return (bp); } +static boolean_t +check_for_pem(char *filename) +{ + char buf[BUFSIZ]; + int len, f; + + if ((f = open(filename, O_RDONLY | O_NONBLOCK)) < 0) + return (FALSE); + + while ((len = read(f, buf, sizeof (buf))) > 0) { + /* Look for "-----BEGIN" right after a newline */ + char *p; + + p = strtok(buf, "\n"); + while (p != NULL) { + if (p < (buf + len)) { + if (strstr(p, "-----BEGIN") != NULL) { + (void) close(f); + return (TRUE); + } + } + p = strtok(NULL, "\n"); + } + } + (void) close(f); + return (FALSE); +} + KMF_RETURN KMF_GetFileFormat(char *filename, KMF_ENCODE_FORMAT *fmt) { @@ -707,9 +735,8 @@ KMF_GetFileFormat(char *filename, KMF_ENCODE_FORMAT *fmt) goto end; } - if (memcmp(buf, "-----BEG", 8) == 0) { - *fmt = KMF_FORMAT_PEM; - } else if (buf[0] == 0x30 && (buf[1] & 0x80)) { + (void) close(f); + if (buf[0] == 0x30 && (buf[1] & 0x80)) { if ((buf[1] & 0xFF) == 0x80 && (buf[2] & 0xFF) == 0x02 && (buf[5] & 0xFF) == 0x30) { @@ -725,12 +752,16 @@ KMF_GetFileFormat(char *filename, KMF_ENCODE_FORMAT *fmt) } else if (memcmp(buf, "Bag Attr", 8) == 0) { *fmt = KMF_FORMAT_PEM_KEYPAIR; } else { - /* Cannot determine this file format */ - *fmt = 0; - ret = KMF_ERR_ENCODING; + /* Try PEM */ + if (check_for_pem(filename) == TRUE) { + *fmt = KMF_FORMAT_PEM; + } else { + /* Cannot determine this file format */ + *fmt = 0; + ret = KMF_ERR_ENCODING; + } } end: - (void) close(f); return (ret); } @@ -1037,6 +1068,8 @@ void KMF_FreeBigint(KMF_BIGINT *big) { if (big != NULL && big->val != NULL) { + /* Clear it out before returning it to the pool */ + (void) memset(big->val, 0x00, big->len); free(big->val); big->val = NULL; big->len = 0; diff --git a/usr/src/lib/libkmf/libkmf/common/kmfoids.c b/usr/src/lib/libkmf/libkmf/common/kmfoids.c index 8bad4388f0..75b5bad7e0 100644 --- a/usr/src/lib/libkmf/libkmf/common/kmfoids.c +++ b/usr/src/lib/libkmf/libkmf/common/kmfoids.c @@ -354,3 +354,28 @@ KMFOID_PKIX_KP_IPSecUser = {OID_PKIX_KP_LENGTH + 1, OID_KP_IPSecUser}, KMFOID_PKIX_KP_TimeStamping = {OID_PKIX_KP_LENGTH + 1, OID_KP_TimeStamping}, KMFOID_PKIX_KP_OCSPSigning = {OID_PKIX_KP_LENGTH + 1, OID_KP_OCSPSigning}; + +static uint8_t +OID_OIW_SHA1[] = { OID_OIW_ALGORITHM, 26}, +OID_OIW_DSA[] = { OID_OIW_ALGORITHM, 12 }, +OID_OIW_DSAWithSHA1[] = { OID_OIW_ALGORITHM, 27 }, +OID_RSAEncryption[] = { OID_PKCS_1, 1 }, +OID_MD2WithRSA[] = { OID_PKCS_1, 2 }, +OID_MD5WithRSA[] = { OID_PKCS_1, 4 }, +OID_SHA1WithRSA[] = { OID_PKCS_1, 5 }, +OID_X9CM_DSA[] = { OID_X9CM_X9ALGORITHM, 1 }, +OID_X9CM_DSAWithSHA1[] = { OID_X9CM_X9ALGORITHM, 3}; + +const KMF_OID +KMFOID_SHA1 = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_SHA1}, +KMFOID_RSA = {OID_PKCS_1_LENGTH+1, OID_RSAEncryption}, +KMFOID_DSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSA}, +KMFOID_MD5WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD5WithRSA}, +KMFOID_MD2WithRSA = {OID_PKCS_1_LENGTH+1, OID_MD2WithRSA}, +KMFOID_SHA1WithRSA = {OID_PKCS_1_LENGTH+1, OID_SHA1WithRSA}, +KMFOID_SHA1WithDSA = {OID_OIW_ALGORITHM_LENGTH+1, OID_OIW_DSAWithSHA1}, +KMFOID_OIW_DSAWithSHA1 = {OID_OIW_ALGORITHM_LENGTH+1, + OID_OIW_DSAWithSHA1}, +KMFOID_X9CM_DSA = {OID_X9CM_X9ALGORITHM_LENGTH+1, OID_X9CM_DSA}, +KMFOID_X9CM_DSAWithSHA1 = {OID_X9CM_X9ALGORITHM_LENGTH+1, + OID_X9CM_DSAWithSHA1}; diff --git a/usr/src/lib/libkmf/libkmf/common/mapfile-vers b/usr/src/lib/libkmf/libkmf/common/mapfile-vers index 044a945d26..fec0c2cee7 100644 --- a/usr/src/lib/libkmf/libkmf/common/mapfile-vers +++ b/usr/src/lib/libkmf/libkmf/common/mapfile-vers @@ -41,6 +41,7 @@ SUNWprivate_1.1 { KMF_CreateSymKey; KMF_DN2Der; KMF_DNParser; + KMF_DecodeCertData; KMF_DecryptWithCert; KMF_DeleteCRL; KMF_DeleteCertFromKeystore; @@ -276,8 +277,19 @@ SUNWprivate_1.1 { KMFOID_X_121Address; KMFOID_domainComponent; KMFOID_userid; + KMFOID_SHA1; + KMFOID_RSA; + KMFOID_DSA; + KMFOID_MD5WithRSA; + KMFOID_MD2WithRSA; + KMFOID_SHA1WithRSA; + KMFOID_SHA1WithDSA; + KMFOID_OIW_DSAWithSHA1; + KMFOID_X9CM_DSA; + KMFOID_X9CM_DSAWithSHA1; PKCS_GetDefaultSignatureMode; PKCS_GetAlgorithmMap; + PKCS_AcquirePublicKeyHandle; X509_AlgIdToAlgorithmOid; X509_AlgorithmOidToAlgId; kmf_ekuname2oid; diff --git a/usr/src/lib/libkmf/libkmf/common/pk11keys.c b/usr/src/lib/libkmf/libkmf/common/pk11keys.c index 90b32053fb..05dded86ea 100644 --- a/usr/src/lib/libkmf/libkmf/common/pk11keys.c +++ b/usr/src/lib/libkmf/libkmf/common/pk11keys.c @@ -316,7 +316,7 @@ cleanup: * - Public Key with label: * Attempts to find a public key with the corresponding label. */ -static KMF_RETURN +KMF_RETURN PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, const KMF_X509_SPKI *pKey, CK_KEY_TYPE ckRequestedKeyType, diff --git a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c index 84af5ad7cd..fc6621e536 100644 --- a/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c +++ b/usr/src/lib/libkmf/plugins/kmf_nss/common/nss_spi.c @@ -35,7 +35,6 @@ #include <kmfapiP.h> #include <ber_der.h> -#include <oidsalg.h> /* NSS related headers */ #include <mps/nss.h> @@ -170,6 +169,7 @@ KMF_PLUGIN_FUNCLIST nss_plugin_table = NSS_CreateSymKey, NSS_GetSymKeyValue, NSS_SetTokenPin, + NULL, /* VerifyData */ NULL /* Finalize */ }; diff --git a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c index dea9bd52d6..8a9fd64815 100644 --- a/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c +++ b/usr/src/lib/libkmf/plugins/kmf_openssl/common/openssl_spi.c @@ -66,7 +66,6 @@ #include <stdlib.h> #include <kmfapiP.h> #include <ber_der.h> -#include <oidsalg.h> #include <fcntl.h> #include <sys/stat.h> #include <dirent.h> @@ -138,12 +137,18 @@ mutex_t init_lock = DEFAULTMUTEX; static int ssl_initialized = 0; static KMF_RETURN -extract_objects(KMF_HANDLE *, char *, CK_UTF8CHAR *, CK_ULONG, - EVP_PKEY **, KMF_DATA **, int *); +extract_objects(KMF_HANDLE *, KMF_FINDCERT_PARAMS *, char *, + CK_UTF8CHAR *, CK_ULONG, EVP_PKEY **, KMF_DATA **, int *); static KMF_RETURN kmf_load_cert(KMF_HANDLE *, KMF_FINDCERT_PARAMS *, char *, KMF_DATA *); +static KMF_RETURN +sslBN2KMFBN(BIGNUM *, KMF_BIGINT *); + +static EVP_PKEY * +ImportRawRSAKey(KMF_RAW_RSA_KEY *); + KMF_RETURN OpenSSL_FindCert(KMF_HANDLE_T, KMF_FINDCERT_PARAMS *, @@ -237,6 +242,10 @@ OpenSSL_VerifyCRLFile(KMF_HANDLE_T, KMF_VERIFYCRL_PARAMS *); KMF_RETURN OpenSSL_CheckCRLDate(KMF_HANDLE_T, KMF_CHECKCRLDATE_PARAMS *); +KMF_RETURN +OpenSSL_VerifyDataWithCert(KMF_HANDLE_T, KMF_ALGORITHM_INDEX, + KMF_DATA *, KMF_DATA *, KMF_DATA *); + static KMF_PLUGIN_FUNCLIST openssl_plugin_table = { @@ -265,6 +274,7 @@ KMF_PLUGIN_FUNCLIST openssl_plugin_table = OpenSSL_CreateSymKey, OpenSSL_GetSymKeyValue, NULL, /* SetTokenPin */ + OpenSSL_VerifyDataWithCert, NULL /* Finalize */ }; @@ -661,7 +671,7 @@ load_certs(KMF_HANDLE *kmfh, KMF_FINDCERT_PARAMS *params, char *pathname, format != KMF_FORMAT_PEM_KEYPAIR) { /* This function only works on PEM files */ - rv = extract_objects(kmfh, pathname, + rv = extract_objects(kmfh, params, pathname, (uchar_t *)NULL, 0, NULL, &certs, &nc); } else { @@ -747,6 +757,162 @@ cleanup: return (rv); } +static KMF_RETURN +readAltFormatPrivateKey(KMF_DATA *filedata, EVP_PKEY **pkey) +{ + KMF_RETURN ret = KMF_OK; + KMF_RAW_RSA_KEY rsa; + BerElement *asn1 = NULL; + BerValue filebuf; + BerValue OID = { NULL, 0 }; + BerValue *Mod = NULL, *PubExp = NULL; + BerValue *PriExp = NULL, *Prime1 = NULL, *Prime2 = NULL; + BerValue *Coef = NULL; + BIGNUM *D = NULL, *P = NULL, *Q = NULL, *COEF = NULL; + BIGNUM *Exp1 = NULL, *Exp2 = NULL, *pminus1 = NULL; + BIGNUM *qminus1 = NULL; + BN_CTX *ctx = NULL; + + *pkey = NULL; + + filebuf.bv_val = (char *)filedata->Data; + filebuf.bv_len = filedata->Length; + + asn1 = kmfder_init(&filebuf); + if (asn1 == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + if (kmfber_scanf(asn1, "{{Dn{IIIIII}}}", + &OID, &Mod, &PubExp, &PriExp, &Prime1, + &Prime2, &Coef) == -1) { + ret = KMF_ERR_ENCODING; + goto out; + } + + /* + * We have to derive the 2 Exponents using Bignumber math. + * Exp1 = PriExp mod (Prime1 - 1) + * Exp2 = PriExp mod (Prime2 - 1) + */ + + /* D = PrivateExponent */ + D = BN_bin2bn((const uchar_t *)PriExp->bv_val, PriExp->bv_len, D); + if (D == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + /* P = Prime1 (first prime factor of Modulus) */ + P = BN_bin2bn((const uchar_t *)Prime1->bv_val, Prime1->bv_len, P); + if (D == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + /* Q = Prime2 (second prime factor of Modulus) */ + Q = BN_bin2bn((const uchar_t *)Prime2->bv_val, Prime2->bv_len, Q); + + if ((ctx = BN_CTX_new()) == NULL) { + ret = KMF_ERR_MEMORY; + goto out; + } + + /* Compute (P - 1) */ + pminus1 = BN_new(); + (void) BN_sub(pminus1, P, BN_value_one()); + + /* Exponent1 = D mod (P - 1) */ + Exp1 = BN_new(); + (void) BN_mod(Exp1, D, pminus1, ctx); + + /* Compute (Q - 1) */ + qminus1 = BN_new(); + (void) BN_sub(qminus1, Q, BN_value_one()); + + /* Exponent2 = D mod (Q - 1) */ + Exp2 = BN_new(); + (void) BN_mod(Exp2, D, qminus1, ctx); + + /* Coef = (Inverse Q) mod P */ + COEF = BN_new(); + (void) BN_mod_inverse(COEF, Q, P, ctx); + + /* Convert back to KMF format */ + (void) memset(&rsa, 0, sizeof (rsa)); + + if ((ret = sslBN2KMFBN(Exp1, &rsa.exp1)) != KMF_OK) + goto out; + if ((ret = sslBN2KMFBN(Exp2, &rsa.exp2)) != KMF_OK) + goto out; + if ((ret = sslBN2KMFBN(COEF, &rsa.coef)) != KMF_OK) + goto out; + + rsa.mod.val = (uchar_t *)Mod->bv_val; + rsa.mod.len = Mod->bv_len; + + rsa.pubexp.val = (uchar_t *)PubExp->bv_val; + rsa.pubexp.len = PubExp->bv_len; + + rsa.priexp.val = (uchar_t *)PriExp->bv_val; + rsa.priexp.len = PriExp->bv_len; + + rsa.prime1.val = (uchar_t *)Prime1->bv_val; + rsa.prime1.len = Prime1->bv_len; + + rsa.prime2.val = (uchar_t *)Prime2->bv_val; + rsa.prime2.len = Prime2->bv_len; + + *pkey = ImportRawRSAKey(&rsa); +out: + if (asn1 != NULL) + kmfber_free(asn1, 1); + + if (OID.bv_val) { + free(OID.bv_val); + } + if (PriExp) + free(PriExp); + + if (Mod) + free(Mod); + + if (PubExp) + free(PubExp); + + if (Coef) { + (void) memset(Coef->bv_val, 0, Coef->bv_len); + free(Coef->bv_val); + free(Coef); + } + if (Prime1) + free(Prime1); + if (Prime2) + free(Prime2); + + if (ctx != NULL) + BN_CTX_free(ctx); + + if (D) + BN_clear_free(D); + if (P) + BN_clear_free(P); + if (Q) + BN_clear_free(Q); + if (pminus1) + BN_clear_free(pminus1); + if (qminus1) + BN_clear_free(qminus1); + if (Exp1) + BN_clear_free(Exp1); + if (Exp2) + BN_clear_free(Exp2); + + return (ret); + +} + static EVP_PKEY * openssl_load_key(KMF_HANDLE_T handle, const char *file) { @@ -754,6 +920,8 @@ openssl_load_key(KMF_HANDLE_T handle, const char *file) EVP_PKEY *pkey = NULL; KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; KMF_ENCODE_FORMAT format; + KMF_RETURN rv; + KMF_DATA filedata; if (file == NULL) { return (NULL); @@ -767,11 +935,48 @@ openssl_load_key(KMF_HANDLE_T handle, const char *file) goto end; } - if (format == KMF_FORMAT_ASN1) + if (format == KMF_FORMAT_ASN1) { pkey = d2i_PrivateKey_bio(keyfile, NULL); - else if (format == KMF_FORMAT_PEM || - format == KMF_FORMAT_PEM_KEYPAIR) + if (pkey == NULL) { + + (void) BIO_free(keyfile); + keyfile = NULL; + /* Try odd ASN.1 variations */ + rv = KMF_ReadInputFile(kmfh, (char *)file, + &filedata); + if (rv == KMF_OK) { + (void) readAltFormatPrivateKey(&filedata, + &pkey); + KMF_FreeData(&filedata); + } + } + } else if (format == KMF_FORMAT_PEM || + format == KMF_FORMAT_PEM_KEYPAIR) { pkey = PEM_read_bio_PrivateKey(keyfile, NULL, NULL, NULL); + if (pkey == NULL) { + KMF_DATA derdata; + /* + * Check if this is the alt. format + * RSA private key file. + */ + rv = KMF_ReadInputFile(kmfh, (char *)file, + &filedata); + if (rv == KMF_OK) { + uchar_t *d = NULL; + int len; + rv = KMF_Pem2Der(filedata.Data, + filedata.Length, &d, &len); + if (rv == KMF_OK && d != NULL) { + derdata.Data = d; + derdata.Length = (size_t)len; + (void) readAltFormatPrivateKey( + &derdata, &pkey); + free(d); + } + KMF_FreeData(&filedata); + } + } + } end: if (pkey == NULL) @@ -1468,6 +1673,7 @@ OpenSSL_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, KMF_ALGORITHM_INDEX AlgId; EVP_MD_CTX ctx; const EVP_MD *md; + if (key == NULL || AlgOID == NULL || tobesigned == NULL || output == NULL || tobesigned->Data == NULL || @@ -1482,33 +1688,44 @@ OpenSSL_SignData(KMF_HANDLE_T handle, KMF_KEY_HANDLE *key, if (key->keyalg == KMF_RSA) { EVP_PKEY *pkey = (EVP_PKEY *)key->keyp; uchar_t *p; - uint32_t len; + int len; if (AlgId == KMF_ALGID_MD5WithRSA) md = EVP_md5(); else if (AlgId == KMF_ALGID_MD2WithRSA) md = EVP_md2(); else if (AlgId == KMF_ALGID_SHA1WithRSA) md = EVP_sha1(); + else if (AlgId == KMF_ALGID_RSA) + md = NULL; else return (KMF_ERR_BAD_PARAMETER); - if (md == NULL) { - SET_ERROR(kmfh, ERR_get_error()); - return (KMF_ERR_MEMORY); - } + if ((md == NULL) && (AlgId == KMF_ALGID_RSA)) { + RSA *rsa = EVP_PKEY_get1_RSA((EVP_PKEY *)pkey); - (void) EVP_MD_CTX_init(&ctx); - (void) EVP_SignInit_ex(&ctx, md, NULL); - (void) EVP_SignUpdate(&ctx, tobesigned->Data, - (uint32_t)tobesigned->Length); - len = (uint32_t)output->Length; - p = output->Data; - if (!EVP_SignFinal(&ctx, p, &len, pkey)) { - SET_ERROR(kmfh, ERR_get_error()); - output->Length = 0; + p = output->Data; + if ((len = RSA_private_encrypt(tobesigned->Length, + tobesigned->Data, p, rsa, + RSA_PKCS1_PADDING)) <= 0) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_INTERNAL; + } + output->Length = len; + } else { + (void) EVP_MD_CTX_init(&ctx); + (void) EVP_SignInit_ex(&ctx, md, NULL); + (void) EVP_SignUpdate(&ctx, tobesigned->Data, + (uint32_t)tobesigned->Length); + len = (uint32_t)output->Length; + p = output->Data; + if (!EVP_SignFinal(&ctx, p, (uint32_t *)&len, pkey)) { + SET_ERROR(kmfh, ERR_get_error()); + len = 0; + ret = KMF_ERR_INTERNAL; + } + output->Length = len; + (void) EVP_MD_CTX_cleanup(&ctx); } - output->Length = len; - (void) EVP_MD_CTX_cleanup(&ctx); } else if (key->keyalg == KMF_DSA) { DSA *dsa = EVP_PKEY_get1_DSA(key->keyp); @@ -2274,7 +2491,7 @@ OpenSSL_GetPrikeyByCert(KMF_HANDLE_T handle, KMF_FINDKEY_PARAMS fkparms; uint32_t numkeys = 0; - if (params == NULL && params->sslparms.keyfile == NULL) + if (params == NULL || params->sslparms.keyfile == NULL) return (KMF_ERR_BAD_PARAMETER); /* @@ -3433,7 +3650,8 @@ end: * However, the file may be just a list of X509 certs with no keys. */ static KMF_RETURN -extract_objects(KMF_HANDLE *kmfh, char *filename, CK_UTF8CHAR *pin, +extract_objects(KMF_HANDLE *kmfh, KMF_FINDCERT_PARAMS *params, + char *filename, CK_UTF8CHAR *pin, CK_ULONG pinlen, EVP_PKEY **priv_key, KMF_DATA **certs, int *numcerts) /* ARGSUSED */ @@ -3441,7 +3659,7 @@ extract_objects(KMF_HANDLE *kmfh, char *filename, CK_UTF8CHAR *pin, KMF_RETURN rv = KMF_OK; FILE *fp; STACK_OF(X509_INFO) *x509_info_stack; - int i, ncerts = 0; + int i, ncerts = 0, matchcerts = 0; EVP_PKEY *pkey = NULL; X509_INFO *info; X509 *x; @@ -3500,21 +3718,34 @@ extract_objects(KMF_HANDLE *kmfh, char *filename, CK_UTF8CHAR *pin, /* * Convert all of the certs to DER format. */ + matchcerts = 0; for (i = 0; rv == KMF_OK && certs != NULL && i < ncerts; i++) { + boolean_t match = FALSE; info = cert_infos[ncerts - 1 - i]; - rv = ssl_cert2KMFDATA(kmfh, info->x509, &certlist[i]); + if (params != NULL) { + rv = check_cert(info->x509, params, &match); + if (rv != KMF_OK || match != TRUE) { + X509_INFO_free(info); + rv = KMF_OK; + continue; + } + } + + rv = ssl_cert2KMFDATA(kmfh, info->x509, + &certlist[matchcerts++]); if (rv != KMF_OK) { free(certlist); certlist = NULL; - ncerts = 0; + ncerts = matchcerts = 0; } + X509_INFO_free(info); } if (numcerts != NULL) - *numcerts = ncerts; + *numcerts = matchcerts; if (certs != NULL) *certs = certlist; @@ -3891,7 +4122,7 @@ openssl_import_keypair(KMF_HANDLE *kmfh, *keylist = NULL; *ncerts = 0; *nkeys = 0; - rv = extract_objects(kmfh, filename, + rv = extract_objects(kmfh, NULL, filename, (uchar_t *)cred->cred, (uint32_t)cred->credlen, &privkey, certlist, ncerts); @@ -4508,3 +4739,203 @@ OpenSSL_GetSymKeyValue(KMF_HANDLE_T handle, KMF_KEY_HANDLE *symkey, return (rv); } + +/* + * id-sha1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) oiw(14) secsig(3) + * algorithms(2) 26 + * } + */ +#define ASN1_SHA1_OID_PREFIX_LEN 15 +static uchar_t SHA1_DER_PREFIX[ASN1_SHA1_OID_PREFIX_LEN] = { + 0x30, 0x21, 0x30, 0x09, + 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14 +}; + +/* + * id-md2 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 + * } + */ +#define ASN1_MD2_OID_PREFIX_LEN 18 +static uchar_t MD2_DER_PREFIX[ASN1_MD2_OID_PREFIX_LEN] = { + 0x30, 0x20, 0x30, 0x0c, + 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x02, 0x05, 0x00, + 0x04, 0x10 +}; + +/* + * id-md5 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 + * } + */ +#define ASN1_MD5_OID_PREFIX_LEN 18 +static uchar_t MD5_DER_PREFIX[ASN1_MD5_OID_PREFIX_LEN] = { + 0x30, 0x20, 0x30, 0x0c, + 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x05, 0x05, 0x00, + 0x04, 0x10 +}; + +KMF_RETURN +OpenSSL_VerifyDataWithCert(KMF_HANDLE_T handle, + KMF_ALGORITHM_INDEX algid, KMF_DATA *indata, + KMF_DATA *insig, KMF_DATA *cert) +{ + KMF_RETURN ret = KMF_OK; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + X509 *xcert = NULL; + EVP_PKEY *pkey = NULL; + uchar_t *p; + uchar_t *rsaout = NULL; + uchar_t *pfx = NULL; + const EVP_MD *md; + int pfxlen = 0, len; + + if (handle == NULL || indata == NULL || + indata->Data == NULL || indata->Length == 0 || + insig == NULL|| insig->Data == NULL || insig->Length == 0 || + cert == NULL || cert->Data == NULL || cert->Length == 0) + return (KMF_ERR_BAD_PARAMETER); + + p = cert->Data; + xcert = d2i_X509(NULL, (const uchar_t **)&p, cert->Length); + if (xcert == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + pkey = X509_get_pubkey(xcert); + if (!pkey) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_CERT_FORMAT; + goto cleanup; + } + + if (algid != KMF_ALGID_NONE) { + switch (algid) { + case KMF_ALGID_MD5WithRSA: + md = EVP_md5(); + break; + case KMF_ALGID_MD2WithRSA: + md = EVP_md2(); + break; + case KMF_ALGID_SHA1WithRSA: + md = EVP_sha1(); + break; + case KMF_ALGID_RSA: + md = NULL; + break; + default: + ret = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + } else { + /* Get the hash type from the cert signature */ + md = EVP_get_digestbyobj(xcert->sig_alg->algorithm); + if (md == NULL) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_PARAMETER; + goto cleanup; + } + } + switch (EVP_MD_type(md)) { + case NID_md2: + case NID_md2WithRSAEncryption: + pfxlen = ASN1_MD2_OID_PREFIX_LEN; + pfx = MD2_DER_PREFIX; + break; + case NID_md5: + case NID_md5WithRSAEncryption: + pfxlen = ASN1_MD5_OID_PREFIX_LEN; + pfx = MD5_DER_PREFIX; + break; + case NID_sha1: + case NID_sha1WithRSAEncryption: + pfxlen = ASN1_SHA1_OID_PREFIX_LEN; + pfx = SHA1_DER_PREFIX; + break; + default: /* Unsupported */ + pfxlen = 0; + pfx = NULL; + break; + } + + /* RSA with no hash is a special case */ + rsaout = malloc(RSA_size(pkey->pkey.rsa)); + if (rsaout == NULL) + return (KMF_ERR_MEMORY); + + /* Decrypt the input signature */ + len = RSA_public_decrypt(insig->Length, + insig->Data, rsaout, pkey->pkey.rsa, RSA_PKCS1_PADDING); + if (len < 1) { + SET_ERROR(kmfh, ERR_get_error()); + ret = KMF_ERR_BAD_PARAMETER; + } else { + size_t hashlen = 0; + uint32_t dlen; + char *digest = NULL; + + /* + * If the AlgId requires it, hash the input data before + * comparing it to the decrypted signature. + */ + if (md) { + EVP_MD_CTX ctx; + + hashlen = md->md_size; + + digest = malloc(hashlen + pfxlen); + if (digest == NULL) + return (KMF_ERR_MEMORY); + /* Add the prefix to the comparison buffer. */ + if (pfx && pfxlen > 0) { + (void) memcpy(digest, pfx, pfxlen); + } + (void) EVP_DigestInit(&ctx, md); + (void) EVP_DigestUpdate(&ctx, indata->Data, + indata->Length); + + /* Add the digest AFTER the ASN1 prefix */ + (void) EVP_DigestFinal(&ctx, + (uchar_t *)digest + pfxlen, &dlen); + + dlen += pfxlen; + } else { + digest = (char *)indata->Data; + dlen = indata->Length; + } + + /* + * The result of the RSA decryption should be ASN1(OID | Hash). + * Compare the output hash to the input data for the final + * result. + */ + if (memcmp(rsaout, digest, dlen)) + ret = KMF_ERR_INTERNAL; + else + ret = KMF_OK; + + /* If we had to allocate space for the digest, free it now */ + if (hashlen) + free(digest); + } +cleanup: + if (pkey) + EVP_PKEY_free(pkey); + + if (xcert) + X509_free(xcert); + + if (rsaout) + free(rsaout); + + return (ret); +} diff --git a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c index cc8a0afc0f..7689574e0c 100644 --- a/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c +++ b/usr/src/lib/libkmf/plugins/kmf_pkcs11/common/pkcs11_spi.c @@ -32,7 +32,6 @@ #include <values.h> #include <kmfapiP.h> -#include <oidsalg.h> #include <ber_der.h> #include <algorithm.h> @@ -129,6 +128,10 @@ KMFPK11_GetSymKeyValue(KMF_HANDLE_T, KMF_KEY_HANDLE *, KMF_RAW_SYM_KEY *); KMF_RETURN KMFPK11_SetTokenPin(KMF_HANDLE_T, KMF_SETPIN_PARAMS *, KMF_CREDENTIAL *); +KMF_RETURN +KMFPK11_VerifyDataWithCert(KMF_HANDLE_T, KMF_ALGORITHM_INDEX, KMF_DATA *, + KMF_DATA *, KMF_DATA *); + static KMF_PLUGIN_FUNCLIST pk11token_plugin_table = { @@ -157,6 +160,7 @@ KMF_PLUGIN_FUNCLIST pk11token_plugin_table = KMFPK11_CreateSymKey, KMFPK11_GetSymKeyValue, KMFPK11_SetTokenPin, + KMFPK11_VerifyDataWithCert, NULL /* Finalize */ }; @@ -2953,3 +2957,176 @@ end: (void) C_CloseSession(session); return (ret); } + +static KMF_RETURN +create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech, + CK_FLAGS wanted_flags) +{ + CK_RV rv; + KMF_RETURN kmf_rv = KMF_OK; + CK_SLOT_ID_PTR pSlotList; + CK_ULONG pulCount; + CK_MECHANISM_INFO info; + int i; + + rv = C_Initialize(NULL); + if ((rv != CKR_OK) && + (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { + kmf_rv = KMF_ERR_UNINITIALIZED; + goto out; + } + + rv = C_GetSlotList(0, NULL, &pulCount); + if (rv != CKR_OK) { + kmf_rv = KMF_ERR_UNINITIALIZED; + goto out; + } + + pSlotList = (CK_SLOT_ID_PTR) malloc(pulCount * sizeof (CK_SLOT_ID)); + if (pSlotList == NULL) { + kmf_rv = KMF_ERR_MEMORY; + goto out; + } + + rv = C_GetSlotList(0, pSlotList, &pulCount); + if (rv != CKR_OK) { + kmf_rv = KMF_ERR_UNINITIALIZED; + goto out; + } + + for (i = 0; i < pulCount; i++) { + rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info); + if (rv == CKR_OK && (info.flags & wanted_flags)) + break; + } + if (i < pulCount) { + rv = C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION, + NULL, NULL, sessionp); + + if (rv != CKR_OK) { + kmf_rv = KMF_ERR_UNINITIALIZED; + } + } else { + kmf_rv = KMF_ERR_UNINITIALIZED; + } + +out: + if (pSlotList != NULL) + free(pSlotList); + return (kmf_rv); + +} +static KMF_RETURN +verify_data(KMF_HANDLE_T handle, + KMF_ALGORITHM_INDEX AlgorithmId, + KMF_X509_SPKI *keyp, + KMF_DATA *data, + KMF_DATA *signed_data) +{ + KMF_RETURN ret; + PKCS_ALGORITHM_MAP *pAlgMap = NULL; + CK_RV ckRv; + CK_MECHANISM ckMechanism; + CK_OBJECT_HANDLE ckKeyHandle; + KMF_BOOL bTempKey; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_SESSION_HANDLE ckSession = NULL; + + if (AlgorithmId == KMF_ALGID_NONE) + return (KMF_ERR_BAD_ALGORITHM); + + pAlgMap = PKCS_GetAlgorithmMap(KMF_ALGCLASS_SIGNATURE, + AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId)); + + if (!pAlgMap) + return (KMF_ERR_BAD_ALGORITHM); + + ret = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism, + CKF_VERIFY); + if (ret != KMF_OK) + return (ret); + + /* Fetch the verifying key */ + ret = PKCS_AcquirePublicKeyHandle(ckSession, keyp, + pAlgMap->key_type, &ckKeyHandle, &bTempKey); + + if (ret != KMF_OK) { + return (ret); + } + + ckMechanism.mechanism = pAlgMap->pkcs_mechanism; + ckMechanism.pParameter = NULL; + ckMechanism.ulParameterLen = 0; + + ckRv = C_VerifyInit(ckSession, &ckMechanism, ckKeyHandle); + if (ckRv != CKR_OK) { + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + SET_ERROR(kmfh, ckRv); + ret = KMF_ERR_INTERNAL; + goto cleanup; + } + + ckRv = C_Verify(ckSession, + (CK_BYTE *)data->Data, + (CK_ULONG)data->Length, + (CK_BYTE *)signed_data->Data, + (CK_ULONG)signed_data->Length); + + if (ckRv != CKR_OK) { + SET_ERROR(kmfh, ckRv); + ret = KMF_ERR_INTERNAL; + } + +cleanup: + if (bTempKey) + (void) C_DestroyObject(ckSession, ckKeyHandle); + + (void) C_CloseSession(ckSession); + + return (ret); +} + +KMF_RETURN +KMFPK11_VerifyDataWithCert(KMF_HANDLE_T handle, + KMF_ALGORITHM_INDEX algid, KMF_DATA *indata, + KMF_DATA *insig, KMF_DATA *SignerCertData) +{ + KMF_RETURN ret = KMF_OK; + KMF_X509_CERTIFICATE *SignerCert = NULL; + KMF_X509_SPKI *pubkey; + + if (handle == NULL || indata == NULL || + indata->Data == NULL || indata->Length == 0 || + insig == NULL|| insig->Data == NULL || insig->Length == 0 || + SignerCertData == NULL || SignerCertData->Data == NULL || + SignerCertData->Length == 0) + return (KMF_ERR_BAD_PARAMETER); + + /* Decode the signer cert so we can get the SPKI data */ + ret = DerDecodeSignedCertificate(SignerCertData, &SignerCert); + if (ret != KMF_OK) + goto cleanup; + + /* Get the public key info from the signer certificate */ + pubkey = &SignerCert->certificate.subjectPublicKeyInfo; + + /* If no algorithm specified, use the certs signature algorithm */ + if (algid == KMF_ALGID_NONE) { + algid = X509_AlgorithmOidToAlgId(CERT_ALG_OID(SignerCert)); + } + + if (algid == KMF_ALGID_NONE) { + ret = KMF_ERR_BAD_ALGORITHM; + } else { + ret = verify_data(handle, algid, pubkey, indata, insig); + } + +cleanup: + if (SignerCert) { + KMF_FreeSignedCert(SignerCert); + free(SignerCert); + } + + return (ret); +} |