/src/ibmswtpm2/src/DuplicationCommands.c
Line | Count | Source |
1 | | /********************************************************************************/ |
2 | | /* */ |
3 | | /* Duplication Commands */ |
4 | | /* Written by Ken Goldman */ |
5 | | /* IBM Thomas J. Watson Research Center */ |
6 | | /* $Id: DuplicationCommands.c 1259 2018-07-10 19:11:09Z kgoldman $ */ |
7 | | /* */ |
8 | | /* Licenses and Notices */ |
9 | | /* */ |
10 | | /* 1. Copyright Licenses: */ |
11 | | /* */ |
12 | | /* - Trusted Computing Group (TCG) grants to the user of the source code in */ |
13 | | /* this specification (the "Source Code") a worldwide, irrevocable, */ |
14 | | /* nonexclusive, royalty free, copyright license to reproduce, create */ |
15 | | /* derivative works, distribute, display and perform the Source Code and */ |
16 | | /* derivative works thereof, and to grant others the rights granted herein. */ |
17 | | /* */ |
18 | | /* - The TCG grants to the user of the other parts of the specification */ |
19 | | /* (other than the Source Code) the rights to reproduce, distribute, */ |
20 | | /* display, and perform the specification solely for the purpose of */ |
21 | | /* developing products based on such documents. */ |
22 | | /* */ |
23 | | /* 2. Source Code Distribution Conditions: */ |
24 | | /* */ |
25 | | /* - Redistributions of Source Code must retain the above copyright licenses, */ |
26 | | /* this list of conditions and the following disclaimers. */ |
27 | | /* */ |
28 | | /* - Redistributions in binary form must reproduce the above copyright */ |
29 | | /* licenses, this list of conditions and the following disclaimers in the */ |
30 | | /* documentation and/or other materials provided with the distribution. */ |
31 | | /* */ |
32 | | /* 3. Disclaimers: */ |
33 | | /* */ |
34 | | /* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ |
35 | | /* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ |
36 | | /* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ |
37 | | /* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ |
38 | | /* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ |
39 | | /* information on specification licensing rights available through TCG */ |
40 | | /* membership agreements. */ |
41 | | /* */ |
42 | | /* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ |
43 | | /* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ |
44 | | /* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ |
45 | | /* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ |
46 | | /* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ |
47 | | /* */ |
48 | | /* - Without limitation, TCG and its members and licensors disclaim all */ |
49 | | /* liability, including liability for infringement of any proprietary */ |
50 | | /* rights, relating to use of information in this specification and to the */ |
51 | | /* implementation of this specification, and TCG disclaims all liability for */ |
52 | | /* cost of procurement of substitute goods or services, lost profits, loss */ |
53 | | /* of use, loss of data or any incidental, consequential, direct, indirect, */ |
54 | | /* or special damages, whether under contract, tort, warranty or otherwise, */ |
55 | | /* arising in any way out of use or reliance upon this specification or any */ |
56 | | /* information herein. */ |
57 | | /* */ |
58 | | /* (c) Copyright IBM Corp. and others, 2016 - 2018 */ |
59 | | /* */ |
60 | | /********************************************************************************/ |
61 | | |
62 | | #include "Tpm.h" |
63 | | #include "Duplicate_fp.h" |
64 | | #if CC_Duplicate // Conditional expansion of this file |
65 | | #include "Object_spt_fp.h" |
66 | | TPM_RC |
67 | | TPM2_Duplicate( |
68 | | Duplicate_In *in, // IN: input parameter list |
69 | | Duplicate_Out *out // OUT: output parameter list |
70 | | ) |
71 | 0 | { |
72 | 0 | TPM_RC result = TPM_RC_SUCCESS; |
73 | 0 | TPMT_SENSITIVE sensitive; |
74 | 0 | UINT16 innerKeySize = 0; // encrypt key size for inner wrap |
75 | 0 | OBJECT *object; |
76 | 0 | OBJECT *newParent; |
77 | 0 | TPM2B_DATA data; |
78 | | // Input Validation |
79 | | // Get duplicate object pointer |
80 | 0 | object = HandleToObject(in->objectHandle); |
81 | | // Get new parent |
82 | 0 | newParent = HandleToObject(in->newParentHandle); |
83 | | // duplicate key must have fixParent bit CLEAR. |
84 | 0 | if(IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, fixedParent)) |
85 | 0 | return TPM_RCS_ATTRIBUTES + RC_Duplicate_objectHandle; |
86 | | // Do not duplicate object with NULL nameAlg |
87 | 0 | if(object->publicArea.nameAlg == TPM_ALG_NULL) |
88 | 0 | return TPM_RCS_TYPE + RC_Duplicate_objectHandle; |
89 | | // new parent key must be a storage object or TPM_RH_NULL |
90 | 0 | if(in->newParentHandle != TPM_RH_NULL |
91 | 0 | && !ObjectIsStorage(in->newParentHandle)) |
92 | 0 | return TPM_RCS_TYPE + RC_Duplicate_newParentHandle; |
93 | | // If the duplicated object has encryptedDuplication SET, then there must be |
94 | | // an inner wrapper and the new parent may not be TPM_RH_NULL |
95 | 0 | if(IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, |
96 | 0 | encryptedDuplication)) |
97 | 0 | { |
98 | 0 | if(in->symmetricAlg.algorithm == TPM_ALG_NULL) |
99 | 0 | return TPM_RCS_SYMMETRIC + RC_Duplicate_symmetricAlg; |
100 | 0 | if(in->newParentHandle == TPM_RH_NULL) |
101 | 0 | return TPM_RCS_HIERARCHY + RC_Duplicate_newParentHandle; |
102 | 0 | } |
103 | 0 | if(in->symmetricAlg.algorithm == TPM_ALG_NULL) |
104 | 0 | { |
105 | | // if algorithm is TPM_ALG_NULL, input key size must be 0 |
106 | 0 | if(in->encryptionKeyIn.t.size != 0) |
107 | 0 | return TPM_RCS_SIZE + RC_Duplicate_encryptionKeyIn; |
108 | 0 | } |
109 | 0 | else |
110 | 0 | { |
111 | | // Get inner wrap key size |
112 | 0 | innerKeySize = in->symmetricAlg.keyBits.sym; |
113 | | // If provided the input symmetric key must match the size of the algorithm |
114 | 0 | if(in->encryptionKeyIn.t.size != 0 |
115 | 0 | && in->encryptionKeyIn.t.size != (innerKeySize + 7) / 8) |
116 | 0 | return TPM_RCS_SIZE + RC_Duplicate_encryptionKeyIn; |
117 | 0 | } |
118 | | // Command Output |
119 | 0 | if(in->newParentHandle != TPM_RH_NULL) |
120 | 0 | { |
121 | | // Make encrypt key and its associated secret structure. A TPM_RC_KEY |
122 | | // error may be returned at this point |
123 | 0 | out->outSymSeed.t.size = sizeof(out->outSymSeed.t.secret); |
124 | 0 | result = CryptSecretEncrypt(newParent, DUPLICATE_STRING, &data, |
125 | 0 | &out->outSymSeed); |
126 | 0 | if(result != TPM_RC_SUCCESS) |
127 | 0 | return result; |
128 | 0 | } |
129 | 0 | else |
130 | 0 | { |
131 | | // Do not apply outer wrapper |
132 | 0 | data.t.size = 0; |
133 | 0 | out->outSymSeed.t.size = 0; |
134 | 0 | } |
135 | | // Copy sensitive area |
136 | 0 | sensitive = object->sensitive; |
137 | | // Prepare output private data from sensitive. |
138 | | // Note: If there is no encryption key, one will be provided by |
139 | | // SensitiveToDuplicate(). This is why the assignment of encryptionKeyIn to |
140 | | // encryptionKeyOut will work properly and is not conditional. |
141 | 0 | SensitiveToDuplicate(&sensitive, &object->name.b, newParent, |
142 | 0 | object->publicArea.nameAlg, &data.b, |
143 | 0 | &in->symmetricAlg, &in->encryptionKeyIn, |
144 | 0 | &out->duplicate); |
145 | 0 | out->encryptionKeyOut = in->encryptionKeyIn; |
146 | 0 | return TPM_RC_SUCCESS; |
147 | 0 | } |
148 | | #endif // CC_Duplicate |
149 | | #include "Tpm.h" |
150 | | #include "Rewrap_fp.h" |
151 | | #if CC_Rewrap // Conditional expansion of this file |
152 | | #include "Object_spt_fp.h" |
153 | | TPM_RC |
154 | | TPM2_Rewrap( |
155 | | Rewrap_In *in, // IN: input parameter list |
156 | | Rewrap_Out *out // OUT: output parameter list |
157 | | ) |
158 | 0 | { |
159 | 0 | TPM_RC result = TPM_RC_SUCCESS; |
160 | 0 | TPM2B_DATA data; // symmetric key |
161 | 0 | UINT16 hashSize = 0; |
162 | 0 | TPM2B_PRIVATE privateBlob; // A temporary private blob |
163 | | // to transit between old |
164 | | // and new wrappers |
165 | | // Input Validation |
166 | 0 | if((in->inSymSeed.t.size == 0 && in->oldParent != TPM_RH_NULL) |
167 | 0 | || (in->inSymSeed.t.size != 0 && in->oldParent == TPM_RH_NULL)) |
168 | 0 | return TPM_RCS_HANDLE + RC_Rewrap_oldParent; |
169 | 0 | if(in->oldParent != TPM_RH_NULL) |
170 | 0 | { |
171 | 0 | OBJECT *oldParent = HandleToObject(in->oldParent); |
172 | | // old parent key must be a storage object |
173 | 0 | if(!ObjectIsStorage(in->oldParent)) |
174 | 0 | return TPM_RCS_TYPE + RC_Rewrap_oldParent; |
175 | | // Decrypt input secret data via asymmetric decryption. A |
176 | | // TPM_RC_VALUE, TPM_RC_KEY or unmarshal errors may be returned at this |
177 | | // point |
178 | 0 | result = CryptSecretDecrypt(oldParent, NULL, DUPLICATE_STRING, |
179 | 0 | &in->inSymSeed, &data); |
180 | 0 | if(result != TPM_RC_SUCCESS) |
181 | 0 | return TPM_RCS_VALUE + RC_Rewrap_inSymSeed; |
182 | | // Unwrap Outer |
183 | 0 | result = UnwrapOuter(oldParent, &in->name.b, |
184 | 0 | oldParent->publicArea.nameAlg, &data.b, |
185 | 0 | FALSE, |
186 | 0 | in->inDuplicate.t.size, in->inDuplicate.t.buffer); |
187 | 0 | if(result != TPM_RC_SUCCESS) |
188 | 0 | return RcSafeAddToResult(result, RC_Rewrap_inDuplicate); |
189 | | // Copy unwrapped data to temporary variable, remove the integrity field |
190 | 0 | hashSize = sizeof(UINT16) + |
191 | 0 | CryptHashGetDigestSize(oldParent->publicArea.nameAlg); |
192 | 0 | privateBlob.t.size = in->inDuplicate.t.size - hashSize; |
193 | 0 | pAssert(privateBlob.t.size <= sizeof(privateBlob.t.buffer)); |
194 | 0 | MemoryCopy(privateBlob.t.buffer, in->inDuplicate.t.buffer + hashSize, |
195 | 0 | privateBlob.t.size); |
196 | 0 | } |
197 | 0 | else |
198 | 0 | { |
199 | | // No outer wrap from input blob. Direct copy. |
200 | 0 | privateBlob = in->inDuplicate; |
201 | 0 | } |
202 | 0 | if(in->newParent != TPM_RH_NULL) |
203 | 0 | { |
204 | 0 | OBJECT *newParent; |
205 | 0 | newParent = HandleToObject(in->newParent); |
206 | | // New parent must be a storage object |
207 | 0 | if(!ObjectIsStorage(in->newParent)) |
208 | 0 | return TPM_RCS_TYPE + RC_Rewrap_newParent; |
209 | | // Make new encrypt key and its associated secret structure. A |
210 | | // TPM_RC_VALUE error may be returned at this point if RSA algorithm is |
211 | | // enabled in TPM |
212 | 0 | out->outSymSeed.t.size = sizeof(out->outSymSeed.t.secret); |
213 | 0 | result = CryptSecretEncrypt(newParent, DUPLICATE_STRING, &data, |
214 | 0 | &out->outSymSeed); |
215 | 0 | if(result != TPM_RC_SUCCESS) |
216 | 0 | return result; |
217 | | // Copy temporary variable to output, reserve the space for integrity |
218 | 0 | hashSize = sizeof(UINT16) + |
219 | 0 | CryptHashGetDigestSize(newParent->publicArea.nameAlg); |
220 | | // Make sure that everything fits into the output buffer |
221 | | // Note: this is mostly only an issue if there was no outer wrapper on |
222 | | // 'inDuplicate'. It could be as large as a TPM2B_PRIVATE buffer. If we add |
223 | | // a digest for an outer wrapper, it won't fit anymore. |
224 | 0 | if((privateBlob.t.size + hashSize) > sizeof(out->outDuplicate.t.buffer)) |
225 | 0 | return TPM_RCS_VALUE + RC_Rewrap_inDuplicate; |
226 | | // Command output |
227 | 0 | out->outDuplicate.t.size = privateBlob.t.size; |
228 | 0 | pAssert(privateBlob.t.size |
229 | 0 | <= sizeof(out->outDuplicate.t.buffer) - hashSize); |
230 | 0 | MemoryCopy(out->outDuplicate.t.buffer + hashSize, privateBlob.t.buffer, |
231 | 0 | privateBlob.t.size); |
232 | | // Produce outer wrapper for output |
233 | 0 | out->outDuplicate.t.size = ProduceOuterWrap(newParent, &in->name.b, |
234 | 0 | newParent->publicArea.nameAlg, |
235 | 0 | &data.b, |
236 | 0 | FALSE, |
237 | 0 | out->outDuplicate.t.size, |
238 | 0 | out->outDuplicate.t.buffer); |
239 | 0 | } |
240 | 0 | else // New parent is a null key so there is no seed |
241 | 0 | { |
242 | 0 | out->outSymSeed.t.size = 0; |
243 | | // Copy privateBlob directly |
244 | 0 | out->outDuplicate = privateBlob; |
245 | 0 | } |
246 | 0 | return TPM_RC_SUCCESS; |
247 | 0 | } |
248 | | #endif // CC_Rewrap |
249 | | #include "Tpm.h" |
250 | | #include "Import_fp.h" |
251 | | #if CC_Import // Conditional expansion of this file |
252 | | #include "Object_spt_fp.h" |
253 | | TPM_RC |
254 | | TPM2_Import( |
255 | | Import_In *in, // IN: input parameter list |
256 | | Import_Out *out // OUT: output parameter list |
257 | | ) |
258 | 0 | { |
259 | 0 | TPM_RC result = TPM_RC_SUCCESS; |
260 | 0 | OBJECT *parentObject; |
261 | 0 | TPM2B_DATA data; // symmetric key |
262 | 0 | TPMT_SENSITIVE sensitive; |
263 | 0 | TPM2B_NAME name; |
264 | 0 | TPMA_OBJECT attributes; |
265 | 0 | UINT16 innerKeySize = 0; // encrypt key size for inner |
266 | | // wrapper |
267 | | // Input Validation |
268 | | // to save typing |
269 | 0 | attributes = in->objectPublic.publicArea.objectAttributes; |
270 | | // FixedTPM and fixedParent must be CLEAR |
271 | 0 | if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedTPM) |
272 | 0 | || IS_ATTRIBUTE(attributes, TPMA_OBJECT, fixedParent)) |
273 | 0 | return TPM_RCS_ATTRIBUTES + RC_Import_objectPublic; |
274 | | // Get parent pointer |
275 | 0 | parentObject = HandleToObject(in->parentHandle); |
276 | 0 | if(!ObjectIsParent(parentObject)) |
277 | 0 | return TPM_RCS_TYPE + RC_Import_parentHandle; |
278 | 0 | if(in->symmetricAlg.algorithm != TPM_ALG_NULL) |
279 | 0 | { |
280 | | // Get inner wrap key size |
281 | 0 | innerKeySize = in->symmetricAlg.keyBits.sym; |
282 | | // Input symmetric key must match the size of algorithm. |
283 | 0 | if(in->encryptionKey.t.size != (innerKeySize + 7) / 8) |
284 | 0 | return TPM_RCS_SIZE + RC_Import_encryptionKey; |
285 | 0 | } |
286 | 0 | else |
287 | 0 | { |
288 | | // If input symmetric algorithm is NULL, input symmetric key size must |
289 | | // be 0 as well |
290 | 0 | if(in->encryptionKey.t.size != 0) |
291 | 0 | return TPM_RCS_SIZE + RC_Import_encryptionKey; |
292 | | // If encryptedDuplication is SET, then the object must have an inner |
293 | | // wrapper |
294 | 0 | if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)) |
295 | 0 | return TPM_RCS_ATTRIBUTES + RC_Import_encryptionKey; |
296 | 0 | } |
297 | | // See if there is an outer wrapper |
298 | 0 | if(in->inSymSeed.t.size != 0) |
299 | 0 | { |
300 | | // in->inParentHandle is a parent, but in order to decrypt an outer wrapper, |
301 | | // it must be able to do key exchange and a symmetric key can't do that. |
302 | 0 | if(parentObject->publicArea.type == TPM_ALG_SYMCIPHER) |
303 | 0 | return TPM_RCS_TYPE + RC_Import_parentHandle; |
304 | | // Decrypt input secret data via asymmetric decryption. TPM_RC_ATTRIBUTES, |
305 | | // TPM_RC_ECC_POINT, TPM_RC_INSUFFICIENT, TPM_RC_KEY, TPM_RC_NO_RESULT, |
306 | | // TPM_RC_SIZE, TPM_RC_VALUE may be returned at this point |
307 | 0 | result = CryptSecretDecrypt(parentObject, NULL, DUPLICATE_STRING, |
308 | 0 | &in->inSymSeed, &data); |
309 | 0 | pAssert(result != TPM_RC_BINDING); |
310 | 0 | if(result != TPM_RC_SUCCESS) |
311 | 0 | return RcSafeAddToResult(result, RC_Import_inSymSeed); |
312 | 0 | } |
313 | 0 | else |
314 | 0 | { |
315 | | // If encrytpedDuplication is set, then the object must have an outer |
316 | | // wrapper |
317 | 0 | if(IS_ATTRIBUTE(attributes, TPMA_OBJECT, encryptedDuplication)) |
318 | 0 | return TPM_RCS_ATTRIBUTES + RC_Import_inSymSeed; |
319 | 0 | data.t.size = 0; |
320 | 0 | } |
321 | | // Compute name of object |
322 | 0 | PublicMarshalAndComputeName(&(in->objectPublic.publicArea), &name); |
323 | 0 | if(name.t.size == 0) |
324 | 0 | return TPM_RCS_HASH + RC_Import_objectPublic; |
325 | | // Retrieve sensitive from private. |
326 | | // TPM_RC_INSUFFICIENT, TPM_RC_INTEGRITY, TPM_RC_SIZE may be returned here. |
327 | 0 | result = DuplicateToSensitive(&in->duplicate.b, &name.b, parentObject, |
328 | 0 | in->objectPublic.publicArea.nameAlg, |
329 | 0 | &data.b, &in->symmetricAlg, |
330 | 0 | &in->encryptionKey.b, &sensitive); |
331 | 0 | if(result != TPM_RC_SUCCESS) |
332 | 0 | return RcSafeAddToResult(result, RC_Import_duplicate); |
333 | | // If the parent of this object has fixedTPM SET, then validate this |
334 | | // object as if it were being loaded so that validation can be skipped |
335 | | // when it is actually loaded. |
336 | 0 | if(IS_ATTRIBUTE(parentObject->publicArea.objectAttributes, TPMA_OBJECT, fixedTPM)) |
337 | 0 | { |
338 | 0 | result = ObjectLoad(NULL, NULL, &in->objectPublic.publicArea, |
339 | 0 | &sensitive, RC_Import_objectPublic, RC_Import_duplicate, |
340 | 0 | NULL); |
341 | 0 | } |
342 | | // Command output |
343 | 0 | if(result == TPM_RC_SUCCESS) |
344 | 0 | { |
345 | | // Prepare output private data from sensitive |
346 | 0 | SensitiveToPrivate(&sensitive, &name.b, parentObject, |
347 | 0 | in->objectPublic.publicArea.nameAlg, |
348 | 0 | &out->outPrivate); |
349 | 0 | } |
350 | 0 | return result; |
351 | 0 | } |
352 | | #endif // CC_Import |