/********************************************************************************/ /* */ /* TPM X509 RSA */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* */ /* Licenses and Notices */ /* */ /* 1. Copyright Licenses: */ /* */ /* - Trusted Computing Group (TCG) grants to the user of the source code in */ /* this specification (the "Source Code") a worldwide, irrevocable, */ /* nonexclusive, royalty free, copyright license to reproduce, create */ /* derivative works, distribute, display and perform the Source Code and */ /* derivative works thereof, and to grant others the rights granted herein. */ /* */ /* - The TCG grants to the user of the other parts of the specification */ /* (other than the Source Code) the rights to reproduce, distribute, */ /* display, and perform the specification solely for the purpose of */ /* developing products based on such documents. */ /* */ /* 2. Source Code Distribution Conditions: */ /* */ /* - Redistributions of Source Code must retain the above copyright licenses, */ /* this list of conditions and the following disclaimers. */ /* */ /* - Redistributions in binary form must reproduce the above copyright */ /* licenses, this list of conditions and the following disclaimers in the */ /* documentation and/or other materials provided with the distribution. */ /* */ /* 3. Disclaimers: */ /* */ /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ /* information on specification licensing rights available through TCG */ /* membership agreements. */ /* */ /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ /* */ /* - Without limitation, TCG and its members and licensors disclaim all */ /* liability, including liability for infringement of any proprietary */ /* rights, relating to use of information in this specification and to the */ /* implementation of this specification, and TCG disclaims all liability for */ /* cost of procurement of substitute goods or services, lost profits, loss */ /* of use, loss of data or any incidental, consequential, direct, indirect, */ /* or special damages, whether under contract, tort, warranty or otherwise, */ /* arising in any way out of use or reliance upon this specification or any */ /* information herein. */ /* */ /* (c) Copyright IBM Corp. and others, 2019 - 2023 */ /* */ /********************************************************************************/ //** Includes #include "Tpm.h" #include "X509.h" #include "TpmASN1_fp.h" #include "X509_RSA_fp.h" #include "X509_spt_fp.h" #include "CryptHash_fp.h" #include "CryptRsa_fp.h" //** Functions #if ALG_RSA //*** X509AddSigningAlgorithmRSA() // This creates the singing algorithm data. // Return Type: INT16 // > 0 number of bytes added // == 0 failure INT16 X509AddSigningAlgorithmRSA( OBJECT* signKey, TPMT_SIG_SCHEME* scheme, ASN1MarshalContext* ctx) { TPM_ALG_ID hashAlg = scheme->details.any.hashAlg; PHASH_DEF hashDef = CryptGetHashDef(hashAlg); // NOT_REFERENCED(signKey); // return failure if hash isn't implemented if(hashDef->hashAlg != hashAlg) return 0; switch(scheme->scheme) { case TPM_ALG_RSASSA: { // if the hash is implemented but there is no PKCS1 OID defined // then this is not a valid signing combination. if(hashDef->PKCS1[0] != ASN1_OBJECT_IDENTIFIER) break; if(ctx == NULL) return 1; return X509PushAlgorithmIdentifierSequence(ctx, hashDef->PKCS1); } case TPM_ALG_RSAPSS: // leave if this is just an implementation check if(ctx == NULL) return 1; // In the case of SHA1, everything is default and RFC4055 says that // implementations that do signature generation MUST omit the parameter // when defaults are used. )-: if(hashDef->hashAlg == TPM_ALG_SHA1) { return X509PushAlgorithmIdentifierSequence(ctx, OID_RSAPSS); } else { // Going to build something that looks like: // SEQUENCE (2 elem) // OBJECT IDENTIFIER 1.2.840.113549.1.1.10 rsaPSS (PKCS #1) // SEQUENCE (3 elem) // [0] (1 elem) // SEQUENCE (2 elem) // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 // NULL // [1] (1 elem) // SEQUENCE (2 elem) // OBJECT IDENTIFIER 1.2.840.113549.1.1.8 pkcs1-MGF // SEQUENCE (2 elem) // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 // NULL // [2] (1 elem) salt length // INTEGER 32 // The indentation is just to keep track of where we are in the // structure ASN1StartMarshalContext(ctx); // SEQUENCE (2 elements) { ASN1StartMarshalContext(ctx); // SEQUENCE (3 elements) { // [2] (1 elem) salt length // INTEGER 32 ASN1StartMarshalContext(ctx); { INT16 saltSize = CryptRsaPssSaltSize( (INT16)hashDef->digestSize, (INT16)signKey->publicArea.unique.rsa.t.size); ASN1PushUINT(ctx, saltSize); } ASN1EndEncapsulation(ctx, ASN1_APPLICAIION_SPECIFIC + 2); // Add the mask generation algorithm // [1] (1 elem) // SEQUENCE (2 elem) 1st // OBJECT IDENTIFIER 1.2.840.113549.1.1.8 pkcs1-MGF // SEQUENCE (2 elem) 2nd // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 // NULL ASN1StartMarshalContext(ctx); // mask context [1] (1 elem) { ASN1StartMarshalContext(ctx); // SEQUENCE (2 elem) 1st // Handle the 2nd Sequence (sequence (object, null)) { // This adds a NULL, then an OID and a SEQUENCE // wrapper. X509PushAlgorithmIdentifierSequence(ctx, hashDef->OID); // add the pkcs1-MGF OID ASN1PushOID(ctx, OID_MGF1); } // End outer sequence ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); } // End the [1] ASN1EndEncapsulation(ctx, ASN1_APPLICAIION_SPECIFIC + 1); // Add the hash algorithm // [0] (1 elem) // SEQUENCE (2 elem) (done by // X509PushAlgorithmIdentifierSequence) // OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 sha-256 (NIST) // NULL ASN1StartMarshalContext(ctx); // [0] (1 elem) { X509PushAlgorithmIdentifierSequence(ctx, hashDef->OID); } ASN1EndEncapsulation(ctx, (ASN1_APPLICAIION_SPECIFIC + 0)); } // SEQUENCE (3 elements) end ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); // RSA PSS OID // OBJECT IDENTIFIER 1.2.840.113549.1.1.10 rsaPSS (PKCS #1) ASN1PushOID(ctx, OID_RSAPSS); } // End Sequence (2 elements) return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); } default: break; } return 0; } //*** X509AddPublicRSA() // This function will add the publicKey description to the DER data. If fillPtr is // NULL, then no data is transferred and this function will indicate if the TPM // has the values for DER-encoding of the public key. // Return Type: INT16 // > 0 number of bytes added // == 0 failure INT16 X509AddPublicRSA(OBJECT* object, ASN1MarshalContext* ctx) { UINT32 exp = object->publicArea.parameters.rsaDetail.exponent; // /* SEQUENCE (2 elem) 1st SEQUENCE (2 elem) 2nd OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption (PKCS #1) NULL BIT STRING (1 elem) SEQUENCE (2 elem) 3rd INTEGER (2048 bit) 2197304513741227955725834199357401 INTEGER 65537 */ // If this is a check to see if the key can be encoded, it can. // Need to mark the end sequence if(ctx == NULL) return 1; ASN1StartMarshalContext(ctx); // SEQUENCE (2 elem) 1st ASN1StartMarshalContext(ctx); // BIT STRING ASN1StartMarshalContext(ctx); // SEQUENCE *(2 elem) 3rd // Get public exponent in big-endian byte order. if(exp == 0) exp = RSA_DEFAULT_PUBLIC_EXPONENT; // Push a 4 byte integer. This might get reduced if there are leading zeros or // extended if the high order byte is negative. ASN1PushUINT(ctx, exp); // Push the public key as an integer ASN1PushInteger(ctx, object->publicArea.unique.rsa.t.size, object->publicArea.unique.rsa.t.buffer); // Embed this in a SEQUENCE tag and length in for the key, exponent sequence ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); // SEQUENCE (3rd) // Embed this in a BIT STRING ASN1EndEncapsulation(ctx, ASN1_BITSTRING); // Now add the formatted SEQUENCE for the RSA public key OID. This is a // fully constructed value so it doesn't need to have a context started X509PushAlgorithmIdentifierSequence(ctx, OID_PKCS1_PUB); return ASN1EndEncapsulation(ctx, ASN1_CONSTRUCTED_SEQUENCE); } #endif // ALG_RSA