| /********************************************************************************/ |
| /* */ |
| /* OpenSSL Crypto Utilities */ |
| /* Written by Ken Goldman */ |
| /* IBM Thomas J. Watson Research Center */ |
| /* */ |
| /* (c) Copyright IBM Corporation 2018 - 2020. */ |
| /* */ |
| /* All rights reserved. */ |
| /* */ |
| /* Redistribution and use in source and binary forms, with or without */ |
| /* modification, are permitted provided that the following conditions are */ |
| /* met: */ |
| /* */ |
| /* Redistributions of source code must retain the above copyright notice, */ |
| /* this list of conditions and the following disclaimer. */ |
| /* */ |
| /* Redistributions in binary form must reproduce the above copyright */ |
| /* notice, this list of conditions and the following disclaimer in the */ |
| /* documentation and/or other materials provided with the distribution. */ |
| /* */ |
| /* Neither the names of the IBM Corporation nor the names of its */ |
| /* contributors may be used to endorse or promote products derived from */ |
| /* this software without specific prior written permission. */ |
| /* */ |
| /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ |
| /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ |
| /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ |
| /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ |
| /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ |
| /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ |
| /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ |
| /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ |
| /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ |
| /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ |
| /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
| /********************************************************************************/ |
| |
| /* These functions are worthwhile sample code that probably (judgment call) do not belong in the TSS |
| library. |
| |
| They abstract out crypto library functions. |
| |
| They show how to convert public or private EC or RSA among PEM format <-> EVP format <-> EC_KEY |
| or RSA format <-> binary arrays <-> TPM format TPM2B_PRIVATE, TPM2B_SENSITIVE, TPM2B_PUBLIC |
| usable for loadexternal or import. |
| |
| There are functions to convert public keys from TPM <-> RSA, ECC <-> PEM, and to verify a TPM |
| signature using a PEM format public key. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <limits.h> |
| |
| #ifndef TPM_TSS_NORSA |
| #include <openssl/rsa.h> |
| #endif /* TPM_TSS_NORSA */ |
| #include <openssl/objects.h> |
| #include <openssl/evp.h> |
| #include <openssl/pem.h> |
| |
| #ifndef TPM_TSS_NOECC |
| #include <openssl/ec.h> |
| #endif |
| |
| #ifndef TPM_TSS_NOFILE |
| #include <ibmtss/tssfile.h> |
| #endif |
| #include <ibmtss/tssutils.h> |
| #include <ibmtss/tssmarshal.h> |
| #include <ibmtss/tsscrypto.h> |
| #include <ibmtss/tsscryptoh.h> |
| #include <ibmtss/Implementation.h> |
| |
| #include "objecttemplates.h" |
| #include "cryptoutils.h" |
| |
| /* verbose tracing flag shared by command line utilities */ |
| |
| int tssUtilsVerbose; |
| |
| /* openssl compatibility functions, during the transition from 1.0.1, 1.0.2, 1.1.0, 1.1.1. Some |
| structures were made opaque, with gettters and setters. Some parameters were made const. Some |
| function names changed. */ |
| |
| /* Some functions add const to parameters as of openssl 1.1.0 */ |
| |
| /* These functions are only required for OpenSSL 1.0. OpenSSL 1.1 has them, and the structures are |
| opaque. */ |
| |
| #if OPENSSL_VERSION_NUMBER < 0x10100000 |
| |
| int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) |
| { |
| if (r == NULL || s == NULL) |
| return 0; |
| BN_clear_free(sig->r); |
| BN_clear_free(sig->s); |
| sig->r = r; |
| sig->s = s; |
| return 1; |
| } |
| |
| void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) |
| { |
| if (pr != NULL) { |
| *pr = sig->r; |
| } |
| if (ps != NULL) { |
| *ps = sig->s; |
| } |
| return; |
| } |
| |
| const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x) |
| { |
| return x->cert_info->signature; |
| } |
| |
| void RSA_get0_key(const RSA *rsaKey, |
| const BIGNUM **n, |
| const BIGNUM **e, |
| const BIGNUM **d) |
| { |
| if (n != NULL) { |
| *n = rsaKey->n; |
| } |
| if (e != NULL) { |
| *e = rsaKey->e; |
| } |
| if (d != NULL) { |
| *d = rsaKey->d; |
| } |
| return; |
| } |
| |
| void RSA_get0_factors(const RSA *rsaKey, |
| const BIGNUM **p, |
| const BIGNUM **q) |
| { |
| if (p != NULL) { |
| *p = rsaKey->p; |
| } |
| if (q != NULL) { |
| *q = rsaKey->q; |
| } |
| return; |
| } |
| |
| #endif /* pre openssl 1.1 */ |
| |
| /* These functions are only required for OpenSSL 1.0.1 OpenSSL 1.0.2 has them, and the structures |
| are opaque. In 1.1.0, the parameters became const. */ |
| |
| #if OPENSSL_VERSION_NUMBER < 0x10002000 |
| |
| void X509_get0_signature(OSSLCONST ASN1_BIT_STRING **psig, |
| OSSLCONST X509_ALGOR **palg, const X509 *x) |
| { |
| *psig = x->signature; |
| *palg = x->sig_alg; |
| return; |
| } |
| |
| #endif /* pre openssl 1.0.2 */ |
| |
| #ifndef TPM_TSS_NOFILE |
| |
| /* getCryptoLibrary() returns a string indicating the underlying crypto library. |
| |
| It can be used for programs that must account for library differences. |
| */ |
| |
| void getCryptoLibrary(const char **name) |
| { |
| *name = "openssl"; |
| return; |
| } |
| |
| /* convertPemToEvpPrivKey() converts a PEM key file to an openssl EVP_PKEY key pair */ |
| |
| TPM_RC convertPemToEvpPrivKey(EVP_PKEY **evpPkey, /* freed by caller */ |
| const char *pemKeyFilename, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| FILE *pemKeyFile = NULL; |
| |
| if (rc == 0) { |
| rc = TSS_File_Open(&pemKeyFile, pemKeyFilename, "rb"); /* closed @2 */ |
| } |
| if (rc == 0) { |
| *evpPkey = PEM_read_PrivateKey(pemKeyFile, NULL, NULL, (void *)password); |
| if (*evpPkey == NULL) { |
| printf("convertPemToEvpPrivKey: Error reading key file %s\n", pemKeyFilename); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (pemKeyFile != NULL) { |
| fclose(pemKeyFile); /* @2 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOFILE */ |
| |
| #ifndef TPM_TSS_NOFILE |
| |
| /* convertPemToEvpPubKey() converts a PEM public key file to an openssl EVP_PKEY public key */ |
| |
| TPM_RC convertPemToEvpPubKey(EVP_PKEY **evpPkey, /* freed by caller */ |
| const char *pemKeyFilename) |
| { |
| TPM_RC rc = 0; |
| FILE *pemKeyFile = NULL; |
| |
| if (rc == 0) { |
| rc = TSS_File_Open(&pemKeyFile, pemKeyFilename, "rb"); /* closed @2 */ |
| } |
| if (rc == 0) { |
| *evpPkey = PEM_read_PUBKEY(pemKeyFile, NULL, NULL, NULL); |
| if (*evpPkey == NULL) { |
| printf("convertPemToEvpPubKey: Error reading key file %s\n", pemKeyFilename); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (pemKeyFile != NULL) { |
| fclose(pemKeyFile); /* @2 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOFILE */ |
| |
| #ifndef TPM_TSS_NOFILE |
| |
| /* convertPemToRsaPrivKey() converts a PEM format keypair file to a library specific RSA key |
| token. |
| |
| The return is void because the structure is opaque to the caller. This accomodates other crypto |
| libraries. |
| |
| rsaKey is an RSA structure |
| */ |
| |
| TPM_RC convertPemToRsaPrivKey(void **rsaKey, /* freed by caller */ |
| const char *pemKeyFilename, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| FILE *pemKeyFile = NULL; |
| |
| if (rc == 0) { |
| rc = TSS_File_Open(&pemKeyFile, pemKeyFilename, "rb"); /* closed @1 */ |
| } |
| if (rc == 0) { |
| *rsaKey = (void *)PEM_read_RSAPrivateKey(pemKeyFile, NULL, NULL, (void *)password); |
| if (*rsaKey == NULL) { |
| printf("convertPemToRsaPrivKey: Error in OpenSSL PEM_read_RSAPrivateKey()\n"); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (pemKeyFile != NULL) { |
| fclose(pemKeyFile); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOFILE */ |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEvpPkeyToEckey retrieves the EC_KEY key token from the EVP_PKEY */ |
| |
| TPM_RC convertEvpPkeyToEckey(EC_KEY **ecKey, /* freed by caller */ |
| EVP_PKEY *evpPkey) |
| { |
| TPM_RC rc = 0; |
| |
| if (rc == 0) { |
| *ecKey = EVP_PKEY_get1_EC_KEY(evpPkey); |
| if (*ecKey == NULL) { |
| printf("convertEvpPkeyToEckey: Error extracting EC key from EVP_PKEY\n"); |
| rc = EXIT_FAILURE; |
| } |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| /* convertEvpPkeyToRsakey() retrieves the RSA key token from the EVP_PKEY */ |
| |
| TPM_RC convertEvpPkeyToRsakey(RSA **rsaKey, /* freed by caller */ |
| EVP_PKEY *evpPkey) |
| { |
| TPM_RC rc = 0; |
| |
| if (rc == 0) { |
| *rsaKey = EVP_PKEY_get1_RSA(evpPkey); |
| if (*rsaKey == NULL) { |
| printf("convertEvpPkeyToRsakey: EVP_PKEY_get1_RSA failed\n"); |
| rc = EXIT_FAILURE; |
| } |
| } |
| return rc; |
| } |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcKeyToPrivateKeyBin() converts an OpenSSL EC_KEY to a binary array |
| |
| FIXME Only supports NIST P256 curve. |
| */ |
| |
| TPM_RC convertEcKeyToPrivateKeyBin(int *privateKeyBytes, |
| uint8_t **privateKeyBin, /* freed by caller */ |
| const EC_KEY *ecKey) |
| { |
| TPM_RC rc = 0; |
| const EC_GROUP *ecGroup = NULL; |
| int nid; |
| const BIGNUM *privateKeyBn = NULL; |
| int bnBytes; |
| |
| /* get the group from the key */ |
| if (rc == 0) { |
| ecGroup = EC_KEY_get0_group(ecKey); |
| if (ecGroup == NULL) { |
| printf("convertEcKeyToPrivateKeyBin: Error extracting EC group from EC key\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| /* and then the curve from the group */ |
| if (rc == 0) { |
| nid = EC_GROUP_get_curve_name(ecGroup); |
| /* map NID to size of private key */ |
| switch (nid) { |
| case NID_X9_62_prime256v1: |
| *privateKeyBytes = 32; |
| break; |
| default: |
| printf("convertEcKeyToPrivateKeyBin: Error, curve NID %u not supported\n", nid); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| /* get the ECC private key as a BIGNUM from the EC_KEY */ |
| if (rc == 0) { |
| privateKeyBn = EC_KEY_get0_private_key(ecKey); |
| } |
| /* sanity check the BN size against the curve */ |
| if (rc == 0) { |
| bnBytes = BN_num_bytes(privateKeyBn); |
| if (bnBytes > *privateKeyBytes) { |
| printf("convertEcKeyToPrivateKeyBin: Error, private key %d bytes too large for curve\n", |
| bnBytes); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| /* allocate a buffer for the private key array based on the curve */ |
| if (rc == 0) { |
| rc = TSS_Malloc(privateKeyBin, *privateKeyBytes); |
| } |
| /* convert the private key bignum to binary */ |
| if (rc == 0) { |
| /* TPM rev 116 required the ECC private key to be zero padded in the duplicate parameter of |
| import */ |
| memset(*privateKeyBin, 0, *privateKeyBytes - bnBytes); |
| BN_bn2bin(privateKeyBn, (*privateKeyBin) + (*privateKeyBytes - bnBytes)); |
| if (tssUtilsVerbose) TSS_PrintAll("convertEcKeyToPrivateKeyBin:", *privateKeyBin, *privateKeyBytes); |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| /* convertRsaKeyToPrivateKeyBin() converts an OpenSSL RSA key token private prime p to a binary |
| array */ |
| |
| TPM_RC convertRsaKeyToPrivateKeyBin(int *privateKeyBytes, |
| uint8_t **privateKeyBin, /* freed by caller */ |
| const RSA *rsaKey) |
| { |
| TPM_RC rc = 0; |
| const BIGNUM *p = NULL; |
| const BIGNUM *q; |
| |
| /* get the private primes */ |
| if (rc == 0) { |
| rc = getRsaKeyParts(NULL, NULL, NULL, &p, &q, rsaKey); |
| } |
| /* allocate a buffer for the private key array */ |
| if (rc == 0) { |
| *privateKeyBytes = BN_num_bytes(p); |
| rc = TSS_Malloc(privateKeyBin, *privateKeyBytes); |
| } |
| /* convert the private key bignum to binary */ |
| if (rc == 0) { |
| BN_bn2bin(p, *privateKeyBin); |
| } |
| return rc; |
| } |
| |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcKeyToPublicKeyBin() converts an OpenSSL EC_KEY public key token to a binary array */ |
| |
| TPM_RC convertEcKeyToPublicKeyBin(int *modulusBytes, |
| uint8_t **modulusBin, /* freed by caller */ |
| const EC_KEY *ecKey) |
| { |
| TPM_RC rc = 0; |
| const EC_POINT *ecPoint = NULL; |
| const EC_GROUP *ecGroup = NULL; |
| |
| if (rc == 0) { |
| ecPoint = EC_KEY_get0_public_key(ecKey); |
| if (ecPoint == NULL) { |
| printf("convertEcKeyToPublicKeyBin: Error extracting EC point from EC public key\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| if (rc == 0) { |
| ecGroup = EC_KEY_get0_group(ecKey); |
| if (ecGroup == NULL) { |
| printf("convertEcKeyToPublicKeyBin: Error extracting EC group from EC public key\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| /* get the public modulus */ |
| if (rc == 0) { |
| *modulusBytes = EC_POINT_point2oct(ecGroup, ecPoint, |
| POINT_CONVERSION_UNCOMPRESSED, |
| NULL, 0, NULL); |
| } |
| if (rc == 0) { |
| rc = TSS_Malloc(modulusBin, *modulusBytes); |
| } |
| if (rc == 0) { |
| EC_POINT_point2oct(ecGroup, ecPoint, |
| POINT_CONVERSION_UNCOMPRESSED, |
| *modulusBin, *modulusBytes, NULL); |
| if (tssUtilsVerbose) TSS_PrintAll("convertEcKeyToPublicKeyBin:", *modulusBin, *modulusBytes); |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| /* convertRsaKeyToPublicKeyBin() converts from an openssl RSA key token to a public modulus */ |
| |
| TPM_RC convertRsaKeyToPublicKeyBin(int *modulusBytes, |
| uint8_t **modulusBin, /* freed by caller */ |
| void *rsaKey) |
| { |
| TPM_RC rc = 0; |
| const BIGNUM *n = NULL; |
| const BIGNUM *e; |
| const BIGNUM *d; |
| |
| /* get the public modulus from the RSA key token */ |
| if (rc == 0) { |
| rc = getRsaKeyParts(&n, &e, &d, NULL, NULL, rsaKey); |
| } |
| if (rc == 0) { |
| *modulusBytes = BN_num_bytes(n); |
| } |
| if (rc == 0) { |
| rc = TSS_Malloc(modulusBin, *modulusBytes); |
| } |
| if (rc == 0) { |
| BN_bn2bin(n, *modulusBin); |
| } |
| return rc; |
| } |
| |
| #ifdef TPM_TPM20 |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcPrivateKeyBinToPrivate() converts an EC 'privateKeyBin' to either a |
| TPM2B_PRIVATE or a TPM2B_SENSITIVE |
| |
| */ |
| |
| TPM_RC convertEcPrivateKeyBinToPrivate(TPM2B_PRIVATE *objectPrivate, |
| TPM2B_SENSITIVE *objectSensitive, |
| int privateKeyBytes, |
| uint8_t *privateKeyBin, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| TPMT_SENSITIVE tSensitive; |
| TPM2B_SENSITIVE bSensitive; |
| |
| if (rc == 0) { |
| if (((objectPrivate == NULL) && (objectSensitive == NULL)) || |
| ((objectPrivate != NULL) && (objectSensitive != NULL))) { |
| printf("convertEcPrivateKeyBinToPrivate: Only one result supported\n"); |
| rc = EXIT_FAILURE; |
| } |
| } |
| /* In some cases, the sensitive data is not encrypted and the integrity value is not present. |
| When an integrity value is not needed, it is not present and it is not represented by an |
| Empty Buffer. |
| |
| In this case, the TPM2B_PRIVATE will just be a marshaled TPM2B_SENSITIVE, which is a |
| marshaled TPMT_SENSITIVE */ |
| |
| /* construct TPMT_SENSITIVE */ |
| if (rc == 0) { |
| /* This shall be the same as the type parameter of the associated public area. */ |
| tSensitive.sensitiveType = TPM_ALG_ECC; |
| tSensitive.seedValue.b.size = 0; |
| /* key password converted to TPM2B */ |
| rc = TSS_TPM2B_StringCopy(&tSensitive.authValue.b, password, |
| sizeof(tSensitive.authValue.t.buffer)); |
| } |
| if (rc == 0) { |
| if (privateKeyBytes > 32) { /* hard code NISTP256 */ |
| printf("convertEcPrivateKeyBinToPrivate: Error, private key size %u not 32\n", |
| privateKeyBytes); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (rc == 0) { |
| tSensitive.sensitive.ecc.t.size = privateKeyBytes; |
| memcpy(tSensitive.sensitive.ecc.t.buffer, privateKeyBin, privateKeyBytes); |
| } |
| /* FIXME common code for EC and RSA */ |
| /* marshal the TPMT_SENSITIVE into a TPM2B_SENSITIVE */ |
| if (rc == 0) { |
| if (objectPrivate != NULL) { |
| uint32_t size = sizeof(bSensitive.t.sensitiveArea); /* max size */ |
| uint8_t *buffer = bSensitive.b.buffer; /* pointer that can move */ |
| bSensitive.t.size = 0; /* required before marshaling */ |
| rc = TSS_TPMT_SENSITIVE_Marshalu(&tSensitive, |
| &bSensitive.b.size, /* marshaled size */ |
| &buffer, /* marshal here */ |
| &size); /* max size */ |
| } |
| else { /* return TPM2B_SENSITIVE */ |
| objectSensitive->t.sensitiveArea = tSensitive; |
| } |
| } |
| /* marshal the TPM2B_SENSITIVE (as a TPM2B_PRIVATE, see above) into a TPM2B_PRIVATE */ |
| if (rc == 0) { |
| if (objectPrivate != NULL) { |
| uint32_t size = sizeof(objectPrivate->t.buffer); /* max size */ |
| uint8_t *buffer = objectPrivate->t.buffer; /* pointer that can move */ |
| objectPrivate->t.size = 0; /* required before marshaling */ |
| rc = TSS_TPM2B_PRIVATE_Marshalu((TPM2B_PRIVATE *)&bSensitive, |
| &objectPrivate->t.size, /* marshaled size */ |
| &buffer, /* marshal here */ |
| &size); /* max size */ |
| } |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| #endif /* TPM_TPM20 */ |
| |
| #ifdef TPM_TPM20 |
| |
| /* convertRsaPrivateKeyBinToPrivate() converts an RSA prime 'privateKeyBin' to either a |
| TPM2B_PRIVATE or a TPM2B_SENSITIVE |
| |
| */ |
| |
| TPM_RC convertRsaPrivateKeyBinToPrivate(TPM2B_PRIVATE *objectPrivate, |
| TPM2B_SENSITIVE *objectSensitive, |
| int privateKeyBytes, |
| uint8_t *privateKeyBin, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| TPMT_SENSITIVE tSensitive; |
| TPM2B_SENSITIVE bSensitive; |
| |
| if (rc == 0) { |
| if (((objectPrivate == NULL) && (objectSensitive == NULL)) || |
| ((objectPrivate != NULL) && (objectSensitive != NULL))) { |
| printf("convertRsaPrivateKeyBinToPrivate: Only one result supported\n"); |
| rc = EXIT_FAILURE; |
| } |
| } |
| /* In some cases, the sensitive data is not encrypted and the integrity value is not present. |
| When an integrity value is not needed, it is not present and it is not represented by an |
| Empty Buffer. |
| |
| In this case, the TPM2B_PRIVATE will just be a marshaled TPM2B_SENSITIVE, which is a |
| marshaled TPMT_SENSITIVE */ |
| |
| /* construct TPMT_SENSITIVE */ |
| if (rc == 0) { |
| /* This shall be the same as the type parameter of the associated public area. */ |
| tSensitive.sensitiveType = TPM_ALG_RSA; |
| /* generate a seed for storage keys */ |
| tSensitive.seedValue.b.size = 32; /* FIXME hard coded seed length */ |
| rc = TSS_RandBytes(tSensitive.seedValue.b.buffer, tSensitive.seedValue.b.size); |
| } |
| /* key password converted to TPM2B */ |
| if (rc == 0) { |
| rc = TSS_TPM2B_StringCopy(&tSensitive.authValue.b, password, |
| sizeof(tSensitive.authValue.t.buffer)); |
| } |
| if (rc == 0) { |
| if ((size_t)privateKeyBytes > sizeof(tSensitive.sensitive.rsa.t.buffer)) { |
| printf("convertRsaPrivateKeyBinToPrivate: " |
| "Error, private key modulus %d greater than %lu\n", |
| privateKeyBytes, (unsigned long)sizeof(tSensitive.sensitive.rsa.t.buffer)); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (rc == 0) { |
| tSensitive.sensitive.rsa.t.size = privateKeyBytes; |
| memcpy(tSensitive.sensitive.rsa.t.buffer, privateKeyBin, privateKeyBytes); |
| } |
| /* FIXME common code for EC and RSA */ |
| /* marshal the TPMT_SENSITIVE into a TPM2B_SENSITIVE */ |
| if (rc == 0) { |
| if (objectPrivate != NULL) { |
| uint32_t size = sizeof(bSensitive.t.sensitiveArea); /* max size */ |
| uint8_t *buffer = bSensitive.b.buffer; /* pointer that can move */ |
| bSensitive.t.size = 0; /* required before marshaling */ |
| rc = TSS_TPMT_SENSITIVE_Marshalu(&tSensitive, |
| &bSensitive.b.size, /* marshaled size */ |
| &buffer, /* marshal here */ |
| &size); /* max size */ |
| } |
| else { /* return TPM2B_SENSITIVE */ |
| objectSensitive->t.sensitiveArea = tSensitive; |
| } |
| } |
| /* marshal the TPM2B_SENSITIVE (as a TPM2B_PRIVATE, see above) into a TPM2B_PRIVATE */ |
| if (rc == 0) { |
| if (objectPrivate != NULL) { |
| uint32_t size = sizeof(objectPrivate->t.buffer); /* max size */ |
| uint8_t *buffer = objectPrivate->t.buffer; /* pointer that can move */ |
| objectPrivate->t.size = 0; /* required before marshaling */ |
| rc = TSS_TPM2B_PRIVATE_Marshalu((TPM2B_PRIVATE *)&bSensitive, |
| &objectPrivate->t.size, /* marshaled size */ |
| &buffer, /* marshal here */ |
| &size); /* max size */ |
| } |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TPM20 */ |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcPublicKeyBinToPublic() converts an EC modulus and other parameters to a TPM2B_PUBLIC |
| |
| FIXME Only supports NIST P256 curve. |
| */ |
| |
| TPM_RC convertEcPublicKeyBinToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| TPMI_ECC_CURVE curveID, |
| int modulusBytes, |
| uint8_t *modulusBin) |
| { |
| TPM_RC rc = 0; |
| |
| scheme = scheme; /* scheme parameter not supported yet */ |
| if (rc == 0) { |
| if (modulusBytes != 65) { /* 1 for compression + 32 + 32 */ |
| printf("convertEcPublicKeyBinToPublic: public modulus expected 65 bytes, actual %u\n", |
| modulusBytes); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (rc == 0) { |
| /* Table 184 - Definition of TPMT_PUBLIC Structure */ |
| objectPublic->publicArea.type = TPM_ALG_ECC; |
| objectPublic->publicArea.nameAlg = nalg; |
| objectPublic->publicArea.objectAttributes.val = TPMA_OBJECT_NODA; |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_USERWITHAUTH; |
| switch (keyType) { |
| case TYPE_SI: |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_SIGN; |
| objectPublic->publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL; |
| objectPublic->publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_ECDSA; |
| break; |
| case TYPE_ST: /* for public part only */ |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_DECRYPT; |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_RESTRICTED; |
| objectPublic->publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES; |
| objectPublic->publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128; |
| objectPublic->publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB; |
| objectPublic->publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL; |
| break; |
| case TYPE_DEN: /* for public and private part */ |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_DECRYPT; |
| objectPublic->publicArea.objectAttributes.val &= ~TPMA_OBJECT_RESTRICTED; |
| objectPublic->publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL; |
| objectPublic->publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_ECDH; |
| break; |
| } |
| objectPublic->publicArea.authPolicy.t.size = 0; |
| /* Table 152 - Definition of TPMU_ASYM_SCHEME Union */ |
| objectPublic->publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = halg; |
| objectPublic->publicArea.parameters.eccDetail.curveID = curveID; |
| objectPublic->publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; |
| objectPublic->publicArea.parameters.eccDetail.kdf.details.mgf1.hashAlg = halg; |
| |
| objectPublic->publicArea.unique.ecc.x.t.size = 32; |
| memcpy(objectPublic->publicArea.unique.ecc.x.t.buffer, modulusBin +1, 32); |
| |
| objectPublic->publicArea.unique.ecc.y.t.size = 32; |
| memcpy(objectPublic->publicArea.unique.ecc.y.t.buffer, modulusBin +33, 32); |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| /* convertRsaPublicKeyBinToPublic() converts a public modulus to a TPM2B_PUBLIC structure. */ |
| |
| TPM_RC convertRsaPublicKeyBinToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| int modulusBytes, |
| uint8_t *modulusBin) |
| { |
| TPM_RC rc = 0; |
| |
| if (rc == 0) { |
| if ((size_t)modulusBytes > sizeof(objectPublic->publicArea.unique.rsa.t.buffer)) { |
| printf("convertRsaPublicKeyBinToPublic: Error, " |
| "public key modulus %d greater than %lu\n", modulusBytes, |
| (unsigned long)sizeof(objectPublic->publicArea.unique.rsa.t.buffer)); |
| rc = EXIT_FAILURE; |
| } |
| } |
| if (rc == 0) { |
| /* Table 184 - Definition of TPMT_PUBLIC Structure */ |
| objectPublic->publicArea.type = TPM_ALG_RSA; |
| objectPublic->publicArea.nameAlg = nalg; |
| objectPublic->publicArea.objectAttributes.val = TPMA_OBJECT_NODA; |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_USERWITHAUTH; |
| switch (keyType) { |
| case TYPE_SI: |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_SIGN; |
| objectPublic->publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL; |
| break; |
| case TYPE_ST: /* for public part only */ |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_DECRYPT; |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_RESTRICTED; |
| objectPublic->publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES; |
| objectPublic->publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128; |
| objectPublic->publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB; |
| break; |
| case TYPE_DEN: /* for public and private part */ |
| objectPublic->publicArea.objectAttributes.val |= TPMA_OBJECT_DECRYPT; |
| objectPublic->publicArea.objectAttributes.val &= ~TPMA_OBJECT_RESTRICTED; |
| objectPublic->publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL; |
| break; |
| } |
| objectPublic->publicArea.authPolicy.t.size = 0; |
| /* Table 182 - Definition of TPMU_PUBLIC_PARMS Union <IN/OUT, S> */ |
| objectPublic->publicArea.parameters.rsaDetail.scheme.scheme = scheme; |
| objectPublic->publicArea.parameters.rsaDetail.scheme.details.rsassa.hashAlg = halg; |
| objectPublic->publicArea.parameters.rsaDetail.keyBits = modulusBytes * 8; |
| objectPublic->publicArea.parameters.rsaDetail.exponent = 0; |
| |
| objectPublic->publicArea.unique.rsa.t.size = modulusBytes; |
| memcpy(objectPublic->publicArea.unique.rsa.t.buffer, modulusBin, modulusBytes); |
| } |
| return rc; |
| } |
| |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcKeyToPrivate() converts an openssl EC_KEY to token to either a TPM2B_PRIVATE or |
| TPM2B_SENSITIVE |
| */ |
| |
| TPM_RC convertEcKeyToPrivate(TPM2B_PRIVATE *objectPrivate, |
| TPM2B_SENSITIVE *objectSensitive, |
| EC_KEY *ecKey, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| int privateKeyBytes; |
| uint8_t *privateKeyBin = NULL; |
| |
| /* convert an openssl EC_KEY token to a binary array */ |
| if (rc == 0) { |
| rc = convertEcKeyToPrivateKeyBin(&privateKeyBytes, |
| &privateKeyBin, /* freed @1 */ |
| ecKey); |
| } |
| if (rc == 0) { |
| rc = convertEcPrivateKeyBinToPrivate(objectPrivate, |
| objectSensitive, |
| privateKeyBytes, |
| privateKeyBin, |
| password); |
| } |
| free(privateKeyBin); /* @1 */ |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| /* convertRsaKeyToPrivate() converts an openssl RSA key token to either a TPM2B_PRIVATE or |
| TPM2B_SENSITIVE |
| */ |
| |
| TPM_RC convertRsaKeyToPrivate(TPM2B_PRIVATE *objectPrivate, |
| TPM2B_SENSITIVE *objectSensitive, |
| RSA *rsaKey, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| int privateKeyBytes; |
| uint8_t *privateKeyBin = NULL; |
| |
| /* convert an openssl RSA key token private prime p to a binary array */ |
| if (rc == 0) { |
| rc = convertRsaKeyToPrivateKeyBin(&privateKeyBytes, |
| &privateKeyBin, /* freed @1 */ |
| rsaKey); |
| } |
| /* convert an RSA prime 'privateKeyBin' to either a TPM2B_PRIVATE or a TPM2B_SENSITIVE */ |
| if (rc == 0) { |
| rc = convertRsaPrivateKeyBinToPrivate(objectPrivate, |
| objectSensitive, |
| privateKeyBytes, |
| privateKeyBin, |
| password); |
| } |
| free(privateKeyBin); /* @1 */ |
| return rc; |
| } |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcKeyToPublic() converts an EC_KEY to a TPM2B_PUBLIC */ |
| |
| TPM_RC convertEcKeyToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| EC_KEY *ecKey) |
| { |
| TPM_RC rc = 0; |
| int modulusBytes; |
| uint8_t *modulusBin = NULL; |
| TPMI_ECC_CURVE curveID; |
| |
| if (rc == 0) { |
| rc = convertEcKeyToPublicKeyBin(&modulusBytes, |
| &modulusBin, /* freed @1 */ |
| ecKey); |
| } |
| if (rc == 0) { |
| rc = getEcCurve(&curveID, ecKey); |
| } |
| if (rc == 0) { |
| rc = convertEcPublicKeyBinToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| curveID, |
| modulusBytes, |
| modulusBin); |
| } |
| free(modulusBin); /* @1 */ |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| /* convertRsaKeyToPublic() converts from an openssl RSA key token to a TPM2B_PUBLIC */ |
| |
| TPM_RC convertRsaKeyToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| void *rsaKey) |
| { |
| TPM_RC rc = 0; |
| int modulusBytes; |
| uint8_t *modulusBin = NULL; |
| |
| /* openssl RSA key token to a public modulus */ |
| if (rc == 0) { |
| rc = convertRsaKeyToPublicKeyBin(&modulusBytes, |
| &modulusBin, /* freed @1 */ |
| rsaKey); |
| } |
| /* public modulus to TPM2B_PUBLIC */ |
| if (rc == 0) { |
| rc = convertRsaPublicKeyBinToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| modulusBytes, |
| modulusBin); |
| } |
| free(modulusBin); /* @1 */ |
| return rc; |
| } |
| |
| #endif |
| |
| #ifndef TPM_TSS_NOFILE |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcPemToKeyPair() converts a PEM file to a TPM2B_PUBLIC and TPM2B_PRIVATE */ |
| |
| TPM_RC convertEcPemToKeyPair(TPM2B_PUBLIC *objectPublic, |
| TPM2B_PRIVATE *objectPrivate, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *pemKeyFilename, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPkey = NULL; |
| EC_KEY *ecKey = NULL; |
| |
| /* convert a PEM file to an openssl EVP_PKEY */ |
| if (rc == 0) { |
| rc = convertPemToEvpPrivKey(&evpPkey, /* freed @1 */ |
| pemKeyFilename, |
| password); |
| } |
| if (rc == 0) { |
| rc = convertEvpPkeyToEckey(&ecKey, /* freed @2 */ |
| evpPkey); |
| } |
| if (rc == 0) { |
| rc = convertEcKeyToPrivate(objectPrivate, /* TPM2B_PRIVATE */ |
| NULL, /* TPM2B_SENSITIVE */ |
| ecKey, |
| password); |
| } |
| if (rc == 0) { |
| rc = convertEcKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| ecKey); |
| } |
| EC_KEY_free(ecKey); /* @2 */ |
| if (evpPkey != NULL) { |
| EVP_PKEY_free(evpPkey); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| #endif |
| #endif |
| |
| #ifndef TPM_TSS_NOFILE |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcPemToPublic() converts an ECC P256 signing public key in PEM format to a |
| TPM2B_PUBLIC */ |
| |
| TPM_RC convertEcPemToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *pemKeyFilename) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPkey = NULL; |
| EC_KEY *ecKey = NULL; |
| |
| if (rc == 0) { |
| rc = convertPemToEvpPubKey(&evpPkey, /* freed @1 */ |
| pemKeyFilename); |
| } |
| if (rc == 0) { |
| rc = convertEvpPkeyToEckey(&ecKey, /* freed @2 */ |
| evpPkey); |
| } |
| if (rc == 0) { |
| rc = convertEcKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| ecKey); |
| } |
| if (ecKey != NULL) { |
| EC_KEY_free(ecKey); /* @2 */ |
| } |
| if (evpPkey != NULL) { |
| EVP_PKEY_free(evpPkey); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| #endif |
| #endif |
| |
| #ifndef TPM_TSS_NOFILE |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NORSA |
| |
| /* convertRsaPemToKeyPair() converts an RSA PEM file to a TPM2B_PUBLIC and TPM2B_PRIVATE */ |
| |
| TPM_RC convertRsaPemToKeyPair(TPM2B_PUBLIC *objectPublic, |
| TPM2B_PRIVATE *objectPrivate, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *pemKeyFilename, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPkey = NULL; |
| RSA *rsaKey = NULL; |
| |
| if (rc == 0) { |
| rc = convertPemToEvpPrivKey(&evpPkey, /* freed @1 */ |
| pemKeyFilename, |
| password); |
| } |
| if (rc == 0) { |
| rc = convertEvpPkeyToRsakey(&rsaKey, /* freed @2 */ |
| evpPkey); |
| } |
| if (rc == 0) { |
| rc = convertRsaKeyToPrivate(objectPrivate, /* TPM2B_PRIVATE */ |
| NULL, /* TPM2B_SENSITIVE */ |
| rsaKey, |
| password); |
| } |
| if (rc == 0) { |
| rc = convertRsaKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| rsaKey); |
| } |
| TSS_RsaFree(rsaKey); /* @2 */ |
| if (evpPkey != NULL) { |
| EVP_PKEY_free(evpPkey); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NORSA */ |
| #endif /* TPM_TPM20 */ |
| #endif /* TPM_TSS_NOFILE */ |
| |
| #ifndef TPM_TSS_NOFILE |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcDerToKeyPair() converts an EC keypair stored in DER to a TPM2B_PUBLIC and |
| TPM2B_SENSITIVE. Useful for LoadExternal. |
| |
| */ |
| |
| TPM_RC convertEcDerToKeyPair(TPM2B_PUBLIC *objectPublic, |
| TPM2B_SENSITIVE *objectSensitive, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *derKeyFilename, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| EC_KEY *ecKey = NULL; |
| unsigned char *derBuffer = NULL; |
| size_t derSize; |
| |
| /* read the DER file */ |
| if (rc == 0) { |
| rc = TSS_File_ReadBinaryFile(&derBuffer, /* freed @1 */ |
| &derSize, |
| derKeyFilename); |
| } |
| if (rc == 0) { |
| const unsigned char *tmpPtr = derBuffer; /* because pointer moves */ |
| ecKey = d2i_ECPrivateKey(NULL, &tmpPtr, derSize); /* freed @2 */ |
| if (ecKey == NULL) { |
| printf("convertEcDerToKeyPair: could not convert key to EC_KEY\n"); |
| rc = TPM_RC_VALUE; |
| } |
| } |
| if (rc == 0) { |
| rc = convertEcKeyToPrivate(NULL, /* TPM2B_PRIVATE */ |
| objectSensitive, /* TPM2B_SENSITIVE */ |
| ecKey, |
| password); |
| } |
| if (rc == 0) { |
| rc = convertEcKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| ecKey); |
| } |
| free(derBuffer); /* @1 */ |
| if (ecKey != NULL) { |
| EC_KEY_free(ecKey); /* @2 */ |
| } |
| return rc; |
| } |
| |
| /* convertEcDerToPublic() converts an EC public key stored in DER to a TPM2B_PUBLIC. Useful to |
| calculate a Name. |
| |
| */ |
| |
| TPM_RC convertEcDerToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *derKeyFilename) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPkey = NULL; |
| EC_KEY *ecKey = NULL; |
| unsigned char *derBuffer = NULL; |
| size_t derSize; |
| |
| /* read the DER file */ |
| if (rc == 0) { |
| rc = TSS_File_ReadBinaryFile(&derBuffer, /* freed @1 */ |
| &derSize, |
| derKeyFilename); |
| } |
| if (rc == 0) { |
| const unsigned char *tmpPtr = derBuffer; /* because pointer moves */ |
| evpPkey = d2i_PUBKEY(NULL, &tmpPtr, derSize); /* freed @2 */ |
| if (evpPkey == NULL) { |
| printf("convertEcDerToPublic: could not convert key to EVP_PKEY\n"); |
| rc = TPM_RC_VALUE; |
| } |
| } |
| if (rc == 0) { |
| rc = convertEvpPkeyToEckey(&ecKey, /* freed @3 */ |
| evpPkey); |
| } |
| if (rc == 0) { |
| rc = convertEcKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| ecKey); |
| } |
| free(derBuffer); /* @1 */ |
| if (evpPkey != NULL) { |
| EVP_PKEY_free(evpPkey); /* @1 */ |
| } |
| if (ecKey != NULL) { |
| EC_KEY_free(ecKey); /* @2 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| #endif |
| #endif |
| |
| #ifndef TPM_TSS_NOFILE |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NORSA |
| |
| /* convertRsaDerToKeyPair() converts an RSA keypair stored in DER to a TPM2B_PUBLIC and |
| TPM2B_SENSITIVE. Useful for LoadExternal. |
| |
| */ |
| |
| TPM_RC convertRsaDerToKeyPair(TPM2B_PUBLIC *objectPublic, |
| TPM2B_SENSITIVE *objectSensitive, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *derKeyFilename, |
| const char *password) |
| { |
| TPM_RC rc = 0; |
| RSA *rsaKey = NULL; |
| unsigned char *derBuffer = NULL; |
| size_t derSize; |
| |
| /* read the DER file */ |
| if (rc == 0) { |
| rc = TSS_File_ReadBinaryFile(&derBuffer, /* freed @1 */ |
| &derSize, |
| derKeyFilename); |
| } |
| if (rc == 0) { |
| const unsigned char *tmpPtr = derBuffer; /* because pointer moves */ |
| rsaKey = d2i_RSAPrivateKey(NULL, &tmpPtr, derSize); /* freed @2 */ |
| if (rsaKey == NULL) { |
| printf("convertRsaDerToKeyPair: could not convert key to RSA\n"); |
| rc = TPM_RC_VALUE; |
| } |
| } |
| if (rc == 0) { |
| rc = convertRsaKeyToPrivate(NULL, /* TPM2B_PRIVATE */ |
| objectSensitive, /* TPM2B_SENSITIVE */ |
| rsaKey, |
| password); |
| } |
| if (rc == 0) { |
| rc = convertRsaKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| rsaKey); |
| } |
| free(derBuffer); /* @1 */ |
| TSS_RsaFree(rsaKey); /* @2 */ |
| return rc; |
| } |
| |
| /* convertRsaDerToPublic() converts an RSA public key stored in DER to a TPM2B_PUBLIC. Useful to |
| calculate a Name. |
| |
| */ |
| |
| TPM_RC convertRsaDerToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *derKeyFilename) |
| { |
| TPM_RC rc = 0; |
| RSA *rsaKey = NULL; |
| unsigned char *derBuffer = NULL; |
| size_t derSize; |
| |
| /* read the DER file */ |
| if (rc == 0) { |
| rc = TSS_File_ReadBinaryFile(&derBuffer, /* freed @1 */ |
| &derSize, |
| derKeyFilename); |
| } |
| if (rc == 0) { |
| const unsigned char *tmpPtr = derBuffer; /* because pointer moves */ |
| rsaKey = d2i_RSA_PUBKEY(NULL, &tmpPtr, derSize); /* freed @2 */ |
| if (rsaKey == NULL) { |
| printf("convertRsaDerToPublic: could not convert key to RSA\n"); |
| rc = TPM_RC_VALUE; |
| } |
| } |
| if (rc == 0) { |
| rc = convertRsaKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| rsaKey); |
| } |
| free(derBuffer); /* @1 */ |
| TSS_RsaFree(rsaKey); /* @2 */ |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NORSA */ |
| #endif /* TPM_TPM20 */ |
| #endif /* TPM_TSS_NOFILE */ |
| |
| #ifndef TPM_TSS_NOFILE |
| #ifdef TPM_TPM20 |
| |
| /* convertRsaPemToPublic() converts an RSA public key in PEM format to a TPM2B_PUBLIC */ |
| |
| TPM_RC convertRsaPemToPublic(TPM2B_PUBLIC *objectPublic, |
| int keyType, |
| TPMI_ALG_SIG_SCHEME scheme, |
| TPMI_ALG_HASH nalg, |
| TPMI_ALG_HASH halg, |
| const char *pemKeyFilename) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPkey = NULL; |
| RSA *rsaKey = NULL; |
| |
| if (rc == 0) { |
| rc = convertPemToEvpPubKey(&evpPkey, /* freed @1 */ |
| pemKeyFilename); |
| } |
| if (rc == 0) { |
| rc = convertEvpPkeyToRsakey(&rsaKey, /* freed @2 */ |
| evpPkey); |
| } |
| if (rc == 0) { |
| rc = convertRsaKeyToPublic(objectPublic, |
| keyType, |
| scheme, |
| nalg, |
| halg, |
| rsaKey); |
| } |
| RSA_free(rsaKey); /* @2 */ |
| if (evpPkey != NULL) { |
| EVP_PKEY_free(evpPkey); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif |
| #endif |
| |
| /* getRsaKeyParts() gets the RSA key parts from an OpenSSL RSA key token. |
| |
| If n is not NULL, returns n, e, and d. If p is not NULL, returns p and q. |
| */ |
| |
| TPM_RC getRsaKeyParts(const BIGNUM **n, |
| const BIGNUM **e, |
| const BIGNUM **d, |
| const BIGNUM **p, |
| const BIGNUM **q, |
| const RSA *rsaKey) |
| { |
| TPM_RC rc = 0; |
| if (n != NULL) { |
| RSA_get0_key(rsaKey, n, e, d); |
| } |
| if (p != NULL) { |
| RSA_get0_factors(rsaKey, p, q); |
| } |
| return rc; |
| } |
| |
| /* returns the type (EVP_PKEY_RSA or EVP_PKEY_EC) of the EVP_PKEY. |
| |
| */ |
| |
| int getRsaPubkeyAlgorithm(EVP_PKEY *pkey) |
| { |
| int pkeyType; /* RSA or EC */ |
| pkeyType = EVP_PKEY_base_id(pkey); |
| return pkeyType; |
| } |
| |
| #ifndef TPM_TSS_NOFILE |
| |
| /* convertPublicToPEM() saves a PEM format public key from a TPM2B_PUBLIC |
| |
| */ |
| |
| TPM_RC convertPublicToPEM(const TPM2B_PUBLIC *public, |
| const char *pemFilename) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPubkey = NULL; /* OpenSSL public key, EVP format */ |
| |
| /* convert TPM2B_PUBLIC to EVP_PKEY */ |
| if (rc == 0) { |
| switch (public->publicArea.type) { |
| #ifndef TPM_TSS_NORSA |
| case TPM_ALG_RSA: |
| rc = convertRsaPublicToEvpPubKey(&evpPubkey, /* freed @1 */ |
| &public->publicArea.unique.rsa); |
| break; |
| #endif /* TPM_TSS_NORSA */ |
| #ifndef TPM_TSS_NOECC |
| case TPM_ALG_ECC: |
| rc = convertEcPublicToEvpPubKey(&evpPubkey, /* freed @1 */ |
| &public->publicArea.unique.ecc); |
| break; |
| #endif /* TPM_TSS_NOECC */ |
| default: |
| printf("convertPublicToPEM: Unknown publicArea.type %04hx unsupported\n", |
| public->publicArea.type); |
| rc = TSS_RC_NOT_IMPLEMENTED; |
| break; |
| } |
| } |
| /* write the openssl structure in PEM format */ |
| if (rc == 0) { |
| rc = convertEvpPubkeyToPem(evpPubkey, |
| pemFilename); |
| |
| } |
| if (evpPubkey != NULL) { |
| EVP_PKEY_free(evpPubkey); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOFILE */ |
| |
| #ifndef TPM_TSS_NORSA |
| |
| /* convertRsaPublicToEvpPubKey() converts an RSA TPM2B_PUBLIC to a EVP_PKEY. |
| |
| */ |
| |
| TPM_RC convertRsaPublicToEvpPubKey(EVP_PKEY **evpPubkey, /* freed by caller */ |
| const TPM2B_PUBLIC_KEY_RSA *tpm2bRsa) |
| { |
| TPM_RC rc = 0; |
| int irc; |
| RSA *rsaPubKey = NULL; |
| |
| if (rc == 0) { |
| *evpPubkey = EVP_PKEY_new(); |
| if (*evpPubkey == NULL) { |
| printf("convertRsaPublicToEvpPubKey: EVP_PKEY failed\n"); |
| rc = TSS_RC_OUT_OF_MEMORY; |
| } |
| } |
| /* TPM to RSA token */ |
| if (rc == 0) { |
| /* public exponent */ |
| unsigned char earr[3] = {0x01, 0x00, 0x01}; |
| rc = TSS_RSAGeneratePublicTokenI |
| ((void **)&rsaPubKey, /* freed as part of EVP_PKEY */ |
| tpm2bRsa->t.buffer, /* public modulus */ |
| tpm2bRsa->t.size, |
| earr, /* public exponent */ |
| sizeof(earr)); |
| } |
| /* RSA token to EVP */ |
| if (rc == 0) { |
| irc = EVP_PKEY_assign_RSA(*evpPubkey, rsaPubKey); |
| if (irc == 0) { |
| TSS_RsaFree(rsaPubKey); /* because not assigned tp EVP_PKEY */ |
| printf("convertRsaPublicToEvpPubKey: EVP_PKEY_assign_RSA failed\n"); |
| rc = TSS_RC_RSA_KEY_CONVERT; |
| } |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NORSA */ |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcPublicToEvpPubKey() converts an EC TPMS_ECC_POINT to an EVP_PKEY. |
| */ |
| |
| TPM_RC convertEcPublicToEvpPubKey(EVP_PKEY **evpPubkey, /* freed by caller */ |
| const TPMS_ECC_POINT *tpmsEccPoint) |
| { |
| TPM_RC rc = 0; |
| int irc; |
| EC_GROUP *ecGroup = NULL; |
| EC_KEY *ecKey = NULL; |
| BIGNUM *x = NULL; /* freed @2 */ |
| BIGNUM *y = NULL; /* freed @3 */ |
| |
| if (rc == 0) { |
| ecKey = EC_KEY_new(); /* freed @1 */ |
| if (ecKey == NULL) { |
| printf("convertEcPublicToEvpPubKey: Error creating EC_KEY\n"); |
| rc = TSS_RC_OUT_OF_MEMORY; |
| } |
| } |
| if (rc == 0) { |
| ecGroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); /* freed @4 */ |
| if (ecGroup == NULL) { |
| printf("convertEcPublicToEvpPubKey: Error in EC_GROUP_new_by_curve_name\n"); |
| rc = TSS_RC_OUT_OF_MEMORY; |
| } |
| } |
| if (rc == 0) { |
| /* returns void */ |
| EC_GROUP_set_asn1_flag(ecGroup, OPENSSL_EC_NAMED_CURVE); |
| } |
| /* assign curve to EC_KEY */ |
| if (rc == 0) { |
| irc = EC_KEY_set_group(ecKey, ecGroup); |
| if (irc != 1) { |
| printf("convertEcPublicToEvpPubKey: Error in EC_KEY_set_group\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| if (rc == 0) { |
| rc = convertBin2Bn(&x, /* freed @2 */ |
| tpmsEccPoint->x.t.buffer, |
| tpmsEccPoint->x.t.size); |
| } |
| if (rc == 0) { |
| rc = convertBin2Bn(&y, /* freed @3 */ |
| tpmsEccPoint->y.t.buffer, |
| tpmsEccPoint->y.t.size); |
| } |
| if (rc == 0) { |
| irc = EC_KEY_set_public_key_affine_coordinates(ecKey, x, y); |
| if (irc != 1) { |
| printf("convertEcPublicToEvpPubKey: " |
| "Error converting public key from X Y to EC_KEY format\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| if (rc == 0) { |
| *evpPubkey = EVP_PKEY_new(); /* freed by caller */ |
| if (*evpPubkey == NULL) { |
| printf("convertEcPublicToEvpPubKey: EVP_PKEY failed\n"); |
| rc = TSS_RC_OUT_OF_MEMORY; |
| } |
| } |
| if (rc == 0) { |
| irc = EVP_PKEY_set1_EC_KEY(*evpPubkey, ecKey); |
| if (irc != 1) { |
| printf("convertEcPublicToEvpPubKey: " |
| "Error converting public key from EC to EVP format\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| if (ecGroup != NULL) { |
| EC_GROUP_free(ecGroup); /* @4 */ |
| } |
| if (ecKey != NULL) { |
| EC_KEY_free(ecKey); /* @1 */ |
| } |
| if (x != NULL) { |
| BN_free(x); /* @2 */ |
| } |
| if (y != NULL) { |
| BN_free(y); /* @3 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| #ifndef TPM_TSS_NOFILE |
| |
| TPM_RC convertEvpPubkeyToPem(EVP_PKEY *evpPubkey, |
| const char *pemFilename) |
| { |
| TPM_RC rc = 0; |
| int irc; |
| FILE *pemFile = NULL; |
| |
| if (rc == 0) { |
| pemFile = fopen(pemFilename, "wb"); /* close @1 */ |
| if (pemFile == NULL) { |
| printf("convertEvpPubkeyToPem: Unable to open PEM file %s for write\n", pemFilename); |
| rc = TSS_RC_FILE_OPEN; |
| } |
| } |
| if (rc == 0) { |
| irc = PEM_write_PUBKEY(pemFile, evpPubkey); |
| if (irc == 0) { |
| printf("convertEvpPubkeyToPem: Unable to write PEM file %s\n", pemFilename); |
| rc = TSS_RC_FILE_WRITE; |
| } |
| } |
| if (pemFile != NULL) { |
| fclose(pemFile); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif |
| #ifndef TPM_TSS_NOFILE |
| |
| /* verifySignatureFromPem() verifies the signature 'tSignature' against the digest 'message' using |
| the public key in the PEM format file 'pemFilename'. |
| |
| */ |
| |
| TPM_RC verifySignatureFromPem(unsigned char *message, |
| unsigned int messageSize, |
| TPMT_SIGNATURE *tSignature, |
| TPMI_ALG_HASH halg, |
| const char *pemFilename) |
| { |
| TPM_RC rc = 0; |
| EVP_PKEY *evpPkey = NULL; /* OpenSSL public key, EVP format */ |
| |
| /* read the public key from PEM format */ |
| if (rc == 0) { |
| rc = convertPemToEvpPubKey(&evpPkey, /* freed @1*/ |
| pemFilename); |
| } |
| /* RSA or EC */ |
| if (rc == 0) { |
| switch(tSignature->sigAlg) { |
| #ifndef TPM_TSS_NORSA |
| case TPM_ALG_RSASSA: |
| case TPM_ALG_RSAPSS: |
| rc = verifyRSASignatureFromEvpPubKey(message, |
| messageSize, |
| tSignature, |
| halg, |
| evpPkey); |
| break; |
| #else |
| halg = halg; |
| #endif /* TPM_TSS_NORSA */ |
| #ifndef TPM_TSS_NOECC |
| case TPM_ALG_ECDSA: |
| rc = verifyEcSignatureFromEvpPubKey(message, |
| messageSize, |
| tSignature, |
| evpPkey); |
| break; |
| #endif /* TPM_TSS_NOECC */ |
| default: |
| printf("verifySignatureFromPem: Unknown signature algorithm %04x\n", tSignature->sigAlg); |
| rc = TSS_RC_BAD_SIGNATURE_ALGORITHM; |
| } |
| } |
| if (evpPkey != NULL) { |
| EVP_PKEY_free(evpPkey); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif |
| |
| #ifndef TPM_TSS_NORSA |
| |
| /* verifyRSASignatureFromEvpPubKey() verifies the signature 'tSignature' against the digest |
| 'message' using the RSA public key in evpPkey. |
| |
| */ |
| |
| TPM_RC verifyRSASignatureFromEvpPubKey(unsigned char *message, |
| unsigned int messageSize, |
| TPMT_SIGNATURE *tSignature, |
| TPMI_ALG_HASH halg, |
| EVP_PKEY *evpPkey) |
| { |
| TPM_RC rc = 0; |
| RSA *rsaPubKey = NULL; /* OpenSSL public key, RSA format */ |
| |
| /* construct the RSA key token */ |
| if (rc == 0) { |
| rsaPubKey = EVP_PKEY_get1_RSA(evpPkey); /* freed @1 */ |
| if (rsaPubKey == NULL) { |
| printf("verifyRSASignatureFromEvpPubKey: EVP_PKEY_get1_RSA failed\n"); |
| rc = TSS_RC_RSA_KEY_CONVERT; |
| } |
| } |
| if (rc == 0) { |
| rc = verifyRSASignatureFromRSA(message, |
| messageSize, |
| tSignature, |
| halg, |
| rsaPubKey); |
| } |
| TSS_RsaFree(rsaPubKey); /* @1 */ |
| return rc; |
| } |
| |
| /* signRSAFromRSA() signs digest to signature, using th4 RSA key rsaKey. */ |
| |
| TPM_RC signRSAFromRSA(uint8_t *signature, size_t *signatureLength, |
| size_t signatureSize, |
| const uint8_t *digest, size_t digestLength, |
| TPMI_ALG_HASH hashAlg, |
| void *rsaKey) |
| { |
| TPM_RC rc = 0; |
| int irc; |
| int nid; /* openssl hash algorithm */ |
| |
| /* map the hash algorithm to the openssl NID */ |
| if (rc == 0) { |
| switch (hashAlg) { |
| case TPM_ALG_SHA1: |
| nid = NID_sha1; |
| break; |
| case TPM_ALG_SHA256: |
| nid = NID_sha256; |
| break; |
| case TPM_ALG_SHA384: |
| nid = NID_sha384; |
| break; |
| case TPM_ALG_SHA512: |
| nid = NID_sha512; |
| break; |
| default: |
| printf("signRSAFromRSA: Error, hash algorithm %04hx unsupported\n", hashAlg); |
| rc = TSS_RC_BAD_HASH_ALGORITHM; |
| } |
| } |
| /* validate that the length of the resulting signature will fit in the |
| signature array */ |
| if (rc == 0) { |
| unsigned int keySize = RSA_size(rsaKey); |
| if (keySize > signatureSize) { |
| printf("signRSAFromRSA: Error, private key length %u > signature buffer %u\n", |
| keySize, (unsigned int)signatureSize); |
| rc = TSS_RC_INSUFFICIENT_BUFFER; |
| } |
| } |
| if (rc == 0) { |
| unsigned int siglen; |
| irc = RSA_sign(nid, |
| digest, digestLength, |
| signature, &siglen, |
| rsaKey); |
| *signatureLength = siglen; |
| if (irc != 1) { |
| printf("signRSAFromRSA: Error in OpenSSL RSA_sign()\n"); |
| rc = TSS_RC_RSA_SIGNATURE; |
| } |
| } |
| return rc; |
| } |
| |
| /* verifyRSASignatureFromRSA() verifies the signature 'tSignature' against the digest 'message' |
| using the RSA public key in the OpenSSL RSA format. |
| |
| Supports RSASSA and RSAPSS schemes. |
| */ |
| |
| TPM_RC verifyRSASignatureFromRSA(unsigned char *message, |
| unsigned int messageSize, |
| TPMT_SIGNATURE *tSignature, |
| TPMI_ALG_HASH halg, |
| void *rsaPubKey) |
| { |
| TPM_RC rc = 0; |
| int irc; |
| int nid = 0; /* initialized these two to suppress false gcc -O3 |
| warnings */ |
| const EVP_MD *md = NULL; |
| /* map from hash algorithm to openssl nid */ |
| if (rc == 0) { |
| switch (halg) { |
| case TPM_ALG_SHA1: |
| nid = NID_sha1; |
| md = EVP_sha1(); |
| break; |
| case TPM_ALG_SHA256: |
| nid = NID_sha256; |
| md = EVP_sha256(); |
| break; |
| case TPM_ALG_SHA384: |
| nid = NID_sha384; |
| md = EVP_sha384(); |
| break; |
| case TPM_ALG_SHA512: |
| nid = NID_sha512; |
| md = EVP_sha512(); |
| break; |
| default: |
| printf("verifyRSASignatureFromRSA: Unknown hash algorithm %04x\n", halg); |
| rc = TSS_RC_BAD_HASH_ALGORITHM; |
| } |
| } |
| /* verify the signature */ |
| if (tSignature->sigAlg == TPM_ALG_RSASSA) { |
| if (rc == 0) { |
| irc = RSA_verify(nid, |
| message, messageSize, |
| tSignature->signature.rsassa.sig.t.buffer, |
| tSignature->signature.rsassa.sig.t.size, |
| rsaPubKey); |
| if (irc != 1) { |
| printf("verifyRSASignatureFromRSA: Bad signature\n"); |
| rc = TSS_RC_RSA_SIGNATURE; |
| } |
| } |
| } |
| else if (tSignature->sigAlg == TPM_ALG_RSAPSS) { |
| uint8_t decryptedSig[sizeof(tSignature->signature.rsapss.sig.t.buffer)]; |
| if (rc == 0) { |
| irc = RSA_public_decrypt(tSignature->signature.rsapss.sig.t.size, |
| tSignature->signature.rsapss.sig.t.buffer, |
| decryptedSig, |
| rsaPubKey, |
| RSA_NO_PADDING); |
| if (irc == -1) { |
| printf("verifyRSASignatureFromRSA: RSAPSS Bad signature\n"); |
| rc = TSS_RC_RSA_SIGNATURE; |
| } |
| } |
| if (rc == 0) { |
| irc = RSA_verify_PKCS1_PSS(rsaPubKey, |
| message, |
| md, |
| decryptedSig, |
| -2); /* salt length recovered from signature*/ |
| if (irc != 1) { |
| printf("verifyRSASignatureFromRSA: RSAPSS Bad signature\n"); |
| rc = TSS_RC_RSA_SIGNATURE; |
| } |
| } |
| } |
| else { |
| printf("verifyRSASignatureFromRSA: Bad signature scheme %04x\n", |
| tSignature->sigAlg); |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NORSA */ |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* verifyEcSignatureFromEvpPubKey() verifies the signature 'tSignature' against the digest 'message' |
| using the EC public key in evpPkey. |
| |
| */ |
| |
| TPM_RC verifyEcSignatureFromEvpPubKey(unsigned char *message, |
| unsigned int messageSize, |
| TPMT_SIGNATURE *tSignature, |
| EVP_PKEY *evpPkey) |
| { |
| TPM_RC rc = 0; |
| int irc; |
| EC_KEY *ecKey = NULL; |
| BIGNUM *r = NULL; |
| BIGNUM *s = NULL; |
| ECDSA_SIG *ecdsaSig = NULL; |
| |
| /* construct the EC key token */ |
| if (rc == 0) { |
| ecKey = EVP_PKEY_get1_EC_KEY(evpPkey); /* freed @1 */ |
| if (ecKey == NULL) { |
| printf("verifyEcSignatureFromEvpPubKey: EVP_PKEY_get1_EC_KEY failed\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| /* construct the ECDSA_SIG signature token */ |
| if (rc == 0) { |
| rc = convertBin2Bn(&r, /* freed @2 */ |
| tSignature->signature.ecdsa.signatureR.t.buffer, |
| tSignature->signature.ecdsa.signatureR.t.size); |
| } |
| if (rc == 0) { |
| rc = convertBin2Bn(&s, /* freed @2 */ |
| tSignature->signature.ecdsa.signatureS.t.buffer, |
| tSignature->signature.ecdsa.signatureS.t.size); |
| } |
| /* ECDSA_SIG_new() allocates an empty ECDSA_SIG structure. */ |
| if (rc == 0) { |
| ecdsaSig = ECDSA_SIG_new(); /* freed @2 */ |
| if (ecdsaSig == NULL) { |
| printf("verifyEcSignatureFromEvpPubKey: Error creating ECDSA_SIG_new\n"); |
| rc = TSS_RC_OUT_OF_MEMORY; |
| } |
| } |
| if (rc == 0) { |
| int irc = ECDSA_SIG_set0(ecdsaSig, r, s); |
| if (irc != 1) { |
| printf("verifyEcSignatureFromEvpPubKey: Error in ECDSA_SIG_set0()\n"); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| /* verify the signature */ |
| if (rc == 0) { |
| irc = ECDSA_do_verify(message, messageSize, |
| ecdsaSig, ecKey); |
| if (irc != 1) { /* quote signature did not verify */ |
| printf("verifyEcSignatureFromEvpPubKey: Bad signature\n"); |
| rc = TSS_RC_EC_SIGNATURE; |
| } |
| } |
| if (ecKey != NULL) { |
| EC_KEY_free(ecKey); /* @1 */ |
| } |
| /* if the ECDSA_SIG was allocated correctly, r and s are implicitly freed */ |
| if (ecdsaSig != NULL) { |
| ECDSA_SIG_free(ecdsaSig); /* @2 */ |
| } |
| /* if not, explicitly free */ |
| else { |
| if (r != NULL) BN_free(r); /* @2 */ |
| if (s != NULL) BN_free(s); /* @2 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| #ifndef TPM_TSS_NOFILE |
| |
| /* verifySignatureFromHmacKey() verifies the signature (MAC) against the digest 'message' |
| using the HMAC key in raw binary format. |
| */ |
| |
| TPM_RC verifySignatureFromHmacKey(unsigned char *message, |
| unsigned int messageSize, |
| TPMT_SIGNATURE *tSignature, |
| TPMI_ALG_HASH halg, |
| const char *hmacKeyFilename) |
| { |
| TPM_RC rc = 0; |
| TPM2B_KEY hmacKey; |
| uint32_t sizeInBytes; |
| |
| /* read the HMAC key */ |
| if (rc == 0) { |
| rc = TSS_File_Read2B(&hmacKey.b, |
| sizeof(hmacKey.t.buffer), |
| hmacKeyFilename); |
| } |
| if (rc == 0) { |
| sizeInBytes = TSS_GetDigestSize(halg); |
| rc = TSS_HMAC_Verify(&tSignature->signature.hmac, |
| &hmacKey, /* input HMAC key */ |
| sizeInBytes, |
| messageSize, message, |
| 0, NULL); |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOFILE */ |
| |
| /* convertRsaBinToTSignature() converts an RSA binary signature to a TPMT_SIGNATURE */ |
| |
| TPM_RC convertRsaBinToTSignature(TPMT_SIGNATURE *tSignature, |
| TPMI_ALG_HASH halg, |
| uint8_t *signatureBin, |
| size_t signatureBinLen) |
| { |
| TPM_RC rc = 0; |
| |
| tSignature->sigAlg = TPM_ALG_RSASSA; |
| tSignature->signature.rsassa.hash = halg; |
| tSignature->signature.rsassa.sig.t.size = (uint16_t)signatureBinLen; |
| memcpy(&tSignature->signature.rsassa.sig.t.buffer, signatureBin, signatureBinLen); |
| return rc; |
| } |
| |
| #ifdef TPM_TPM20 |
| #ifndef TPM_TSS_NOECC |
| |
| /* convertEcBinToTSignature() converts an EC binary signature to a TPMT_SIGNATURE */ |
| |
| TPM_RC convertEcBinToTSignature(TPMT_SIGNATURE *tSignature, |
| TPMI_ALG_HASH halg, |
| const uint8_t *signatureBin, |
| size_t signatureBinLen) |
| { |
| TPM_RC rc = 0; |
| ECDSA_SIG *ecSig = NULL; |
| int rBytes; |
| int sBytes; |
| const BIGNUM *pr = NULL; |
| const BIGNUM *ps = NULL; |
| |
| if (rc == 0) { |
| tSignature->sigAlg = TPM_ALG_ECDSA; |
| tSignature->signature.ecdsa.hash = halg; |
| } |
| /* convert DER to ECDSA_SIG */ |
| if (rc == 0) { |
| ecSig = d2i_ECDSA_SIG(NULL, &signatureBin, signatureBinLen); /* freed @1 */ |
| if (ecSig == NULL) { |
| printf("convertEcBinToTSignature: could not convert signature to ECDSA_SIG\n"); |
| rc = TPM_RC_VALUE; |
| } |
| } |
| /* check that the signature size agrees with the currently hard coded P256 curve */ |
| if (rc == 0) { |
| ECDSA_SIG_get0(ecSig, &pr, &ps); |
| rBytes = BN_num_bytes(pr); |
| sBytes = BN_num_bytes(ps); |
| if ((rBytes > 32) || |
| (sBytes > 32)) { |
| printf("convertEcBinToTSignature: signature rBytes %u or sBytes %u greater than 32\n", |
| rBytes, sBytes); |
| rc = TPM_RC_VALUE; |
| } |
| } |
| /* extract the raw signature bytes from the openssl structure BIGNUMs */ |
| if (rc == 0) { |
| tSignature->signature.ecdsa.signatureR.t.size = rBytes; |
| tSignature->signature.ecdsa.signatureS.t.size = sBytes; |
| |
| BN_bn2bin(pr, (unsigned char *)&tSignature->signature.ecdsa.signatureR.t.buffer); |
| BN_bn2bin(ps, (unsigned char *)&tSignature->signature.ecdsa.signatureS.t.buffer); |
| if (tssUtilsVerbose) { |
| TSS_PrintAll("convertEcBinToTSignature: signature R", |
| tSignature->signature.ecdsa.signatureR.t.buffer, |
| tSignature->signature.ecdsa.signatureR.t.size); |
| TSS_PrintAll("convertEcBinToTSignature: signature S", |
| tSignature->signature.ecdsa.signatureS.t.buffer, |
| tSignature->signature.ecdsa.signatureS.t.size); |
| } |
| } |
| if (ecSig != NULL) { |
| ECDSA_SIG_free(ecSig); /* @1 */ |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| |
| #ifndef TPM_TSS_NOECC |
| |
| /* getEcCurve() gets the TCG algorithm ID curve associated with the openssl EC_KEY */ |
| |
| TPM_RC getEcCurve(TPMI_ECC_CURVE *curveID, |
| const EC_KEY *ecKey) |
| { |
| TPM_RC rc = 0; |
| const EC_GROUP *ecGroup; |
| int nid; |
| |
| if (rc == 0) { |
| ecGroup = EC_KEY_get0_group(ecKey); |
| nid = EC_GROUP_get_curve_name(ecGroup); /* openssl NID */ |
| /* NID to TCG curve ID */ |
| switch (nid) { |
| case NID_X9_62_prime256v1: |
| *curveID = TPM_ECC_NIST_P256; |
| break; |
| default: |
| printf("getEcCurve: Error, curve NID %u not supported \n", nid); |
| rc = TSS_RC_EC_KEY_CONVERT; |
| } |
| } |
| return rc; |
| } |
| |
| #endif /* TPM_TSS_NOECC */ |
| #endif |
| |
| /* convertBin2Bn() wraps the openSSL function in an error handler |
| |
| Converts a char array to bignum |
| */ |
| |
| TPM_RC convertBin2Bn(BIGNUM **bn, /* freed by caller */ |
| const unsigned char *bin, |
| unsigned int bytes) |
| { |
| TPM_RC rc = 0; |
| |
| /* BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret); |
| |
| BN_bin2bn() converts the positive integer in big-endian form of length len at s into a BIGNUM |
| and places it in ret. If ret is NULL, a new BIGNUM is created. |
| |
| BN_bin2bn() returns the BIGNUM, NULL on error. |
| */ |
| if (rc == 0) { |
| *bn = BN_bin2bn(bin, bytes, *bn); |
| if (*bn == NULL) { |
| printf("convertBin2Bn: Error in BN_bin2bn\n"); |
| rc = TSS_RC_BIGNUM; |
| } |
| } |
| return rc; |
| } |
| |