/* Microsoft Reference Implementation for TPM 2.0 | |
* | |
* The copyright in this software is being made available under the BSD License, | |
* included below. This software may be subject to other third party and | |
* contributor rights, including patent rights, and no such rights are granted | |
* under this license. | |
* | |
* Copyright (c) Microsoft Corporation | |
* | |
* All rights reserved. | |
* | |
* BSD License | |
* | |
* 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. | |
* | |
* 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. | |
*/ | |
//** 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 |