blob: 9e37f0da13e4806e50bc425f0acaa8f86bb86f7f [file] [log] [blame]
/* 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.
*/
//** Introduction
// This file contains the functions that are used for the two-phase, ECC,
// key-exchange protocols
#include "Tpm.h"
#if CC_ZGen_2Phase == YES //%
//** Functions
#ifdef TPM_ALG_ECMQV
//*** avf1()
// This function does the associated value computation required by MQV key
// exchange.
// Process:
// 1. Convert xQ to an integer xqi using the convention specified in Appendix C.3.
// 2. Calculate
// xqm = xqi mod 2^ceil(f/2) (where f = ceil(log2(n)).
// 3. Calculate the associate value function
// avf(Q) = xqm + 2ceil(f / 2)
static BOOL
avf1(
bigNum bnX, // IN/OUT: the reduced value
bigNum bnN // IN: the order of the curve
)
{
// compute f = 2^(ceil(ceil(log2(n)) / 2))
int f = (BnSizeInBits(bnN) + 1) / 2;
// x' = 2^f + (x mod 2^f)
BnMaskBits(bnX, f); // This is mod 2*2^f but it doesn't matter because
// the next operation will SET the extra bit anyway
BnSetBit(bnX, f);
return TRUE;
}
//*** C_2_2_MQV()
// This function performs the key exchange defined in SP800-56A
// 6.1.1.4 Full MQV, C(2, 2, ECC MQV).
//
// CAUTION: Implementation of this function may require use of essential claims in
// patents not owned by TCG members.
//
// Points QsB and QeB are required to be on the curve of inQsA. The function will
// fail, possibly catastrophically, if this is not the case.
// return type: TPM_RC
// TPM_RC_SUCCESS results is valid
// TPM_RC_NO_RESULTS the value for dsA does not give a valid point on the
// curve
static TPM_RC
C_2_2_MQV(
TPMS_ECC_POINT *outZ, // OUT: the computed point
TPM_ECC_CURVE curveId, // IN: the curve for the computations
TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
TPMS_ECC_POINT *QsB, // IN: static public party B key
TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
)
{
CURVE_INITIALIZED(E, curveId);
ECC_CURVE_DATA *C = AccessCurveData(E);
POINT(pQeA);
POINT_INITIALIZED(pQeB, QeB);
POINT_INITIALIZED(pQsB, QsB);
ECC_NUM(bnTa);
ECC_INITIALIZED(bnDeA, deA);
ECC_INITIALIZED(bnDsA, dsA);
ECC_NUM(bnN);
ECC_NUM(bnXeB);
TPM_RC retVal;
//
// Parameter checks
if(E == NULL)
ERROR_RETURN(TPM_RC_VALUE);
pAssert(outZ != NULL && pQeB != NULL && pQsB != NULL && deA != NULL
&& dsA != NULL);
// Process:
// 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
// 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
// 3. If P = O, output an error indicator.
// 4. Z=xP, where xP is the x-coordinate of P.
// Compute the public ephemeral key pQeA = [de,A]G
if((retVal = BnPointMult(pQeA, CurveGetG(C), bnDeA, NULL, NULL, E))
!= TPM_RC_SUCCESS)
goto Exit;
// 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n.
// tA := (ds,A + de,A avf(Xe,A)) mod n (3)
// Compute 'tA' = ('deA' + 'dsA' avf('XeA')) mod n
// Ta = avf(XeA);
BnCopy(bnTa, pQeA->x);
avf1(bnTa, bnN);
// do Ta = ds,A * Ta mod n = dsA * avf(XeA) mod n
BnModMult(bnTa, bnDsA, bnTa, bnN);
// now Ta = deA + Ta mod n = deA + dsA * avf(XeA) mod n
BnAdd(bnTa, bnTa, bnDeA);
BnMod(bnTa, bnN);
// 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B).
// Put this in because almost every case of h is == 1 so skip the call when
// not necessary.
if(!BnEqualWord(CurveGetCofactor(C), 1))
// Cofactor is not 1 so compute Ta := Ta * h mod n
BnModMult(bnTa, bnTa, CurveGetCofactor(C), CurveGetOrder(C));
// Now that 'tA' is (h * 'tA' mod n)
// 'outZ' = (tA)(Qe,B + avf(Qe,B)Qs,B).
// first, compute XeB = avf(XeB)
avf1(bnXeB, bnN);
// QsB := [XeB]QsB
BnPointMult(pQsB, pQsB, bnXeB, NULL, NULL, E);
BnEccAdd(pQeB, pQeB, pQsB, E);
// QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
// If the result is not the point at infinity, return QeB
BnPointMult(pQeB, pQeB, bnTa, NULL, NULL, E);
if(BnEqualZero(pQeB->z))
ERROR_RETURN(TPM_RC_NO_RESULT);
// Convert BIGNUM E to TPM2B E
BnPointTo2B(outZ, pQeB, E);
Exit:
CURVE_FREE(E);
return retVal;
}
#endif // TPM_ALG_ECMQV
//*** C_2_2_ECDH()
// This function performs the two phase key exchange defined in SP800-56A,
// 6.1.1.2 Full Unified Model, C(2, 2, ECC CDH).
//
static TPM_RC
C_2_2_ECDH(
TPMS_ECC_POINT *outZs, // OUT: Zs
TPMS_ECC_POINT *outZe, // OUT: Ze
TPM_ECC_CURVE curveId, // IN: the curve for the computations
TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
TPMS_ECC_POINT *QsB, // IN: static public party B key
TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
)
{
CURVE_INITIALIZED(E, curveId);
ECC_INITIALIZED(bnAs, dsA);
ECC_INITIALIZED(bnAe, deA);
POINT_INITIALIZED(ecBs, QsB);
POINT_INITIALIZED(ecBe, QeB);
POINT(ecZ);
TPM_RC retVal;
//
// Parameter checks
if(E == NULL)
ERROR_RETURN(TPM_RC_CURVE);
pAssert(outZs != NULL && dsA != NULL && deA != NULL && QsB != NULL
&& QeB != NULL);
// Do the point multiply for the Zs value ([dsA]QsB)
retVal = BnPointMult(ecZ, ecBs, bnAs, NULL, NULL, E);
if(retVal == TPM_RC_SUCCESS)
{
// Convert the Zs value.
BnPointTo2B(outZs, ecZ, E);
// Do the point multiply for the Ze value ([deA]QeB)
retVal = BnPointMult(ecZ, ecBe, bnAe, NULL, NULL, E);
if(retVal == TPM_RC_SUCCESS)
BnPointTo2B(outZe, ecZ, E);
}
Exit:
CURVE_FREE(E);
return retVal;
}
//*** CryptEcc2PhaseKeyExchange()
// This function is the dispatch routine for the EC key exchange functions that use
// two ephemeral and two static keys.
// return type: TPM_RC
// TPM_RC_SCHEME scheme is not defined
LIB_EXPORT TPM_RC
CryptEcc2PhaseKeyExchange(
TPMS_ECC_POINT *outZ1, // OUT: a computed point
TPMS_ECC_POINT *outZ2, // OUT: and optional second point
TPM_ECC_CURVE curveId, // IN: the curve for the computations
TPM_ALG_ID scheme, // IN: the key exchange scheme
TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key
TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key
TPMS_ECC_POINT *QsB, // IN: static public party B key
TPMS_ECC_POINT *QeB // IN: ephemeral public party B key
)
{
pAssert(outZ1 != NULL
&& dsA != NULL && deA != NULL
&& QsB != NULL && QeB != NULL);
// Initialize the output points so that they are empty until one of the
// functions decides otherwise
outZ1->x.b.size = 0;
outZ1->y.b.size = 0;
if(outZ2 != NULL)
{
outZ2->x.b.size = 0;
outZ2->y.b.size = 0;
}
switch(scheme)
{
case TPM_ALG_ECDH:
return C_2_2_ECDH(outZ1, outZ2, curveId, dsA, deA, QsB, QeB);
break;
#ifdef TPM_ALG_ECMQV
case TPM_ALG_ECMQV:
return C_2_2_MQV(outZ1, curveId, dsA, deA, QsB, QeB);
break;
#endif
#ifdef TPM_ALG_SM2
case TPM_ALG_SM2:
return SM2KeyExchange(outZ1, curveId, dsA, deA, QsB, QeB);
break;
#endif
default:
return TPM_RC_SCHEME;
}
}
#ifdef TPM_ALG_SM2
//*** ComputeWForSM2()
// Compute the value for w used by SM2
static UINT32
ComputeWForSM2(
bigCurve E
)
{
// w := ceil(ceil(log2(n)) / 2) - 1
return (BnMsb(CurveGetOrder(AccessCurveData(E))) / 2 - 1);
}
//*** avfSm2()
// This function does the associated value computation required by SM2 key
// exchange. This is different form the avf() in the international standards
// because it returns a value that is half the size of the value returned by the
// standard avf. For example, if n is 15, Ws (w in the standard) is 2 but the W
// here is 1. This means that an input value of 14 (1110b) would return a value
// of 110b with the standard but 10b with the scheme in SM2.
static bigNum
avfSm2(
bigNum bn, // IN/OUT: the reduced value
UINT32 w // IN: the value of w
)
{
// a) set w := ceil(ceil(log2(n)) / 2) - 1
// b) set x' := 2^w + ( x & (2^w - 1))
// This is just like the avf for MQV where x' = 2^w + (x mod 2^w)
BnMaskBits(bn, w); // as with avf1, this is too big by a factor of 2 but
// it doesn't matter because we SET the extra bit
// anyway
BnSetBit(bn, w);
return bn;
}
// SM2KeyExchange()
// This function performs the key exchange defined in SM2.
// The first step is to compute
// 'tA' = ('dsA' + 'deA' avf(Xe,A)) mod n
// Then, compute the Z value from
// 'outZ' = ('h' 'tA' mod 'n') ('QsA' + [avf(QeB.x)](QeB)).
// The function will compute the ephemeral public key from the ephemeral
// private key.
// All points are required to be on the curve of inQsA. The function will fail
// catastrophically if this is not the case
// return type: TPM_RC
// TPM_RC_SUCCESS results is valid
// TPM_RC_NO_RESULTS the value for dsA does not give a valid point on the
// curve
LIB_EXPORT TPM_RC
SM2KeyExchange(
TPMS_ECC_POINT *outZ, // OUT: the computed point
TPM_ECC_CURVE curveId, // IN: the curve for the computations
TPM2B_ECC_PARAMETER *dsAIn, // IN: static private TPM key
TPM2B_ECC_PARAMETER *deAIn, // IN: ephemeral private TPM key
TPMS_ECC_POINT *QsBIn, // IN: static public party B key
TPMS_ECC_POINT *QeBIn // IN: ephemeral public party B key
)
{
CURVE_INITIALIZED(E, curveId);
const ECC_CURVE_DATA *C = (E != NULL) ? AccessCurveData(E) : NULL;
ECC_INITIALIZED(dsA, dsAIn);
ECC_INITIALIZED(deA, deAIn);
POINT_INITIALIZED(QsB, QsBIn);
POINT_INITIALIZED(QeB, QeBIn);
BN_WORD_INITIALIZED(One, 1);
POINT(QeA);
ECC_NUM(XeB);
POINT(Z);
ECC_NUM(Ta);
UINT32 w;
TPM_RC retVal = TPM_RC_NO_RESULT;
//
// Parameter checks
if(E == NULL)
ERROR_RETURN(TPM_RC_CURVE);
pAssert(outZ != NULL && dsA != NULL && deA != NULL && QsB != NULL
&& QeB != NULL);
// Compute the value for w
w = ComputeWForSM2(E);
// Compute the public ephemeral key pQeA = [de,A]G
if(!BnEccModMult(QeA, CurveGetG(C), deA, E))
goto Exit;
// tA := (ds,A + de,A avf(Xe,A)) mod n (3)
// Compute 'tA' = ('dsA' + 'deA' avf('XeA')) mod n
// Ta = avf(XeA);
// do Ta = de,A * Ta = deA * avf(XeA)
BnMult(Ta, deA, avfSm2(QeA->x, w));
// now Ta = dsA + Ta = dsA + deA * avf(XeA)
BnAdd(Ta, dsA, Ta);
BnMod(Ta, CurveGetOrder(C));
// outZ = [h tA mod n] (Qs,B + [avf(Xe,B)](Qe,B)) (4)
// Put this in because almost every case of h is == 1 so skip the call when
// not necessary.
if(!BnEqualWord(CurveGetCofactor(C), 1))
// Cofactor is not 1 so compute Ta := Ta * h mod n
BnModMult(Ta, Ta, CurveGetCofactor(C), CurveGetOrder(C));
// Now that 'tA' is (h * 'tA' mod n)
// 'outZ' = ['tA'](QsB + [avf(QeB.x)](QeB)).
BnCopy(XeB, QeB->x);
if(!BnEccModMult2(Z, QsB, One, QeB, avfSm2(XeB, w), E))
goto Exit;
// QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity
if(!BnEccModMult(Z, Z, Ta, E))
goto Exit;
// Convert BIGNUM E to TPM2B E
BnPointTo2B(outZ, Z, E);
retVal = TPM_RC_SUCCESS;
Exit:
CURVE_FREE(E);
return retVal;
}
#endif
#endif //% CC_ZGen_2Phase