1 // This file was extracted from the TCG Published
2 // Trusted Platform Module Library
3 // Part 3: Commands
4 // Family "2.0"
5 // Level 00 Revision 01.16
6 // October 30, 2014
7 
8 #include "InternalRoutines.h"
9 #include "Duplicate_fp.h"
10 #include "Object_spt_fp.h"
11 //
12 //
13 //     Error Returns                Meaning
14 //
15 //     TPM_RC_ATTRIBUTES            key to duplicate has fixedParent SET
16 //     TPM_RC_HIERARCHY             encryptedDuplication is SET and newParentHandle specifies Null
17 //                                  Hierarchy
18 //     TPM_RC_KEY                   newParentHandle references invalid ECC key (public point not on the
19 //                                  curve)
20 //     TPM_RC_SIZE                  input encryption key size does not match the size specified in
21 //                                  symmetric algorithm
22 //     TPM_RC_SYMMETRIC             encryptedDuplication is SET but no symmetric algorithm is provided
23 //     TPM_RC_TYPE                  newParentHandle is neither a storage key nor TPM_RH_NULL; or
24 //                                  the object has a NULL nameAlg
25 //
26 TPM_RC
TPM2_Duplicate(Duplicate_In * in,Duplicate_Out * out)27 TPM2_Duplicate(
28    Duplicate_In      *in,            // IN: input parameter list
29    Duplicate_Out     *out            // OUT: output parameter list
30    )
31 {
32    TPM_RC                   result = TPM_RC_SUCCESS;
33    TPMT_SENSITIVE           sensitive;
34 
35    UINT16                   innerKeySize = 0; // encrypt key size for inner wrap
36 
37    OBJECT                   *object;
38    TPM2B_DATA               data;
39 
40 // Input Validation
41 
42    // Get duplicate object pointer
43    object = ObjectGet(in->objectHandle);
44 
45    // duplicate key must have fixParent bit CLEAR.
46    if(object->publicArea.objectAttributes.fixedParent == SET)
47        return TPM_RC_ATTRIBUTES + RC_Duplicate_objectHandle;
48 
49    // Do not duplicate object with NULL nameAlg
50    if(object->publicArea.nameAlg == TPM_ALG_NULL)
51        return TPM_RC_TYPE + RC_Duplicate_objectHandle;
52 
53    // new parent key must be a storage object or TPM_RH_NULL
54    if(in->newParentHandle != TPM_RH_NULL
55            && !ObjectIsStorage(in->newParentHandle))
56        return TPM_RC_TYPE + RC_Duplicate_newParentHandle;
57 
58    // If the duplicates object has encryptedDuplication SET, then there must be
59    // an inner wrapper and the new parent may not be TPM_RH_NULL
60    if(object->publicArea.objectAttributes.encryptedDuplication == SET)
61    {
62        if(in->symmetricAlg.algorithm == TPM_ALG_NULL)
63            return TPM_RC_SYMMETRIC + RC_Duplicate_symmetricAlg;
64        if(in->newParentHandle == TPM_RH_NULL)
65             return TPM_RC_HIERARCHY + RC_Duplicate_newParentHandle;
66    }
67 
68    if(in->symmetricAlg.algorithm == TPM_ALG_NULL)
69    {
70        // if algorithm is TPM_ALG_NULL, input key size must be 0
71        if(in->encryptionKeyIn.t.size != 0)
72            return TPM_RC_SIZE + RC_Duplicate_encryptionKeyIn;
73    }
74    else
75    {
76        // Get inner wrap key size
77        innerKeySize = in->symmetricAlg.keyBits.sym;
78 
79        // If provided the input symmetric key must match the size of the algorithm
80        if(in->encryptionKeyIn.t.size != 0
81                && in->encryptionKeyIn.t.size != (innerKeySize + 7) / 8)
82            return TPM_RC_SIZE + RC_Duplicate_encryptionKeyIn;
83    }
84 
85 // Command Output
86 
87    if(in->newParentHandle != TPM_RH_NULL)
88    {
89 
90        // Make encrypt key and its associated secret structure. A TPM_RC_KEY
91        // error may be returned at this point
92        out->outSymSeed.t.size = sizeof(out->outSymSeed.t.secret);
93        result = CryptSecretEncrypt(in->newParentHandle,
94                                    "DUPLICATE", &data, &out->outSymSeed);
95        pAssert(result != TPM_RC_VALUE);
96        if(result != TPM_RC_SUCCESS)
97            return result;
98    }
99    else
100    {
101        // Do not apply outer wrapper
102        data.t.size = 0;
103        out->outSymSeed.t.size = 0;
104    }
105 
106    // Copy sensitive area
107    sensitive = object->sensitive;
108 
109    // Prepare output private data from sensitive
110    SensitiveToDuplicate(&sensitive, &object->name, in->newParentHandle,
111                         object->publicArea.nameAlg, (TPM2B_SEED *) &data,
112                         &in->symmetricAlg, &in->encryptionKeyIn,
113                         &out->duplicate);
114 
115    out->encryptionKeyOut = in->encryptionKeyIn;
116 
117    return TPM_RC_SUCCESS;
118 }
119