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 "Rewrap_fp.h"
10#include "Object_spt_fp.h"
11//
12//
13//     Error Returns                 Meaning
14//
15//     TPM_RC_ATTRIBUTES             newParent is not a decryption key
16//     TPM_RC_HANDLE                 oldParent does not consistent with inSymSeed
17//     TPM_RC_INTEGRITY              the integrity check of inDuplicate failed
18//     TPM_RC_KEY                    for an ECC key, the public key is not on the curve of the curve ID
19//     TPM_RC_KEY_SIZE               the decrypted input symmetric key size does not matches the
20//                                   symmetric algorithm key size of oldParent
21//     TPM_RC_TYPE                   oldParent is not a storage key, or 'newParent is not a storage key
22//     TPM_RC_VALUE                  for an 'oldParent; RSA key, the data to be decrypted is greater than
23//                                   the public exponent
24//     Unmarshal errors              errors during unmarshaling the input encrypted buffer to a ECC public
25//                                   key, or unmarshal the private buffer to sensitive
26//
27TPM_RC
28TPM2_Rewrap(
29   Rewrap_In         *in,             // IN: input parameter list
30   Rewrap_Out        *out             // OUT: output parameter list
31   )
32{
33   TPM_RC                   result = TPM_RC_SUCCESS;
34   OBJECT                   *oldParent;
35   TPM2B_DATA               data;               // symmetric key
36   UINT16                   hashSize = 0;
37   TPM2B_PRIVATE            privateBlob;        // A temporary private blob
38                                                // to transit between old
39                                                // and new wrappers
40
41// Input Validation
42
43   if((in->inSymSeed.t.size == 0 && in->oldParent != TPM_RH_NULL)
44           || (in->inSymSeed.t.size != 0 && in->oldParent == TPM_RH_NULL))
45       return TPM_RC_HANDLE + RC_Rewrap_oldParent;
46
47   if(in->oldParent != TPM_RH_NULL)
48   {
49       // Get old parent pointer
50       oldParent = ObjectGet(in->oldParent);
51
52         // old parent key must be a storage object
53         if(!ObjectIsStorage(in->oldParent))
54             return TPM_RC_TYPE + RC_Rewrap_oldParent;
55
56         // Decrypt input secret data via asymmetric decryption. A
57         // TPM_RC_VALUE, TPM_RC_KEY or unmarshal errors may be returned at this
58         // point
59         result = CryptSecretDecrypt(in->oldParent, NULL,
60                                     "DUPLICATE", &in->inSymSeed, &data);
61         if(result != TPM_RC_SUCCESS)
62             return TPM_RC_VALUE + RC_Rewrap_inSymSeed;
63
64       // Unwrap Outer
65       result = UnwrapOuter(in->oldParent, &in->name,
66                            oldParent->publicArea.nameAlg, (TPM2B_SEED *) &data,
67                            FALSE,
68                            in->inDuplicate.t.size, in->inDuplicate.t.buffer);
69       if(result != TPM_RC_SUCCESS)
70           return RcSafeAddToResult(result, RC_Rewrap_inDuplicate);
71
72       // Copy unwrapped data to temporary variable, remove the integrity field
73       hashSize = sizeof(UINT16) +
74                  CryptGetHashDigestSize(oldParent->publicArea.nameAlg);
75       privateBlob.t.size = in->inDuplicate.t.size - hashSize;
76       MemoryCopy(privateBlob.t.buffer, in->inDuplicate.t.buffer + hashSize,
77                  privateBlob.t.size, sizeof(privateBlob.t.buffer));
78   }
79   else
80   {
81       // No outer wrap from input blob.   Direct copy.
82       privateBlob = in->inDuplicate;
83   }
84
85   if(in->newParent != TPM_RH_NULL)
86   {
87       OBJECT          *newParent;
88       newParent = ObjectGet(in->newParent);
89
90       // New parent must be a storage object
91       if(!ObjectIsStorage(in->newParent))
92           return TPM_RC_TYPE + RC_Rewrap_newParent;
93
94       // Make new encrypt key and its associated secret structure. A
95       // TPM_RC_VALUE error may be returned at this point if RSA algorithm is
96       // enabled in TPM
97       out->outSymSeed.t.size = sizeof(out->outSymSeed.t.secret);
98       result = CryptSecretEncrypt(in->newParent,
99                                   "DUPLICATE", &data, &out->outSymSeed);
100       if(result != TPM_RC_SUCCESS) return result;
101
102// Command output
103       // Copy temporary variable to output, reserve the space for integrity
104       hashSize = sizeof(UINT16) +
105                  CryptGetHashDigestSize(newParent->publicArea.nameAlg);
106       out->outDuplicate.t.size = privateBlob.t.size;
107       MemoryCopy(out->outDuplicate.t.buffer + hashSize, privateBlob.t.buffer,
108                  privateBlob.t.size, sizeof(out->outDuplicate.t.buffer));
109
110       // Produce outer wrapper for output
111       out->outDuplicate.t.size = ProduceOuterWrap(in->newParent, &in->name,
112                                  newParent->publicArea.nameAlg,
113                                  (TPM2B_SEED *) &data,
114                                  FALSE,
115                                  out->outDuplicate.t.size,
116                                  out->outDuplicate.t.buffer);
117
118   }
119   else // New parent is a null key so there is no seed
120   {
121       out->outSymSeed.t.size = 0;
122
123       // Copy privateBlob directly
124       out->outDuplicate = privateBlob;
125   }
126
127   return TPM_RC_SUCCESS;
128}
129