1 /********************************************************************************/
2 /* */
3 /* TSS Library Independent Crypto Support */
4 /* Written by Ken Goldman */
5 /* IBM Thomas J. Watson Research Center */
6 /* */
7 /* (c) Copyright IBM Corporation 2015 - 2019. */
8 /* */
9 /* All rights reserved. */
10 /* */
11 /* Redistribution and use in source and binary forms, with or without */
12 /* modification, are permitted provided that the following conditions are */
13 /* met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright notice, */
16 /* this list of conditions and the following disclaimer. */
17 /* */
18 /* Redistributions in binary form must reproduce the above copyright */
19 /* notice, this list of conditions and the following disclaimer in the */
20 /* documentation and/or other materials provided with the distribution. */
21 /* */
22 /* Neither the names of the IBM Corporation nor the names of its */
23 /* contributors may be used to endorse or promote products derived from */
24 /* this software without specific prior written permission. */
25 /* */
26 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
27 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
28 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
29 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
30 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
31 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
32 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
33 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
34 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
35 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
36 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
37 /********************************************************************************/
38
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43
44 #ifdef TPM_POSIX
45 #include <netinet/in.h>
46 #endif
47 #ifdef TPM_WINDOWS
48 #include <winsock2.h>
49 #endif
50
51 #include <ibmtss/tssresponsecode.h>
52 #include <ibmtss/tssutils.h>
53 #include <ibmtss/tssprint.h>
54 #include <ibmtss/tsserror.h>
55
56 #include <ibmtss/tsscryptoh.h>
57 #include <ibmtss/tsscrypto.h>
58
59 extern int tssVverbose;
60 extern int tssVerbose;
61
62 /* local prototypes */
63
64 static TPM_RC TSS_MGF1(unsigned char *mask,
65 uint32_t maskLen,
66 const unsigned char *mgfSeed,
67 uint16_t mgfSeedlen,
68 TPMI_ALG_HASH halg);
69
70 /* TSS_HMAC_Generate() can be called directly to HMAC a list of streams.
71
72 The ... arguments are a message list of the form
73 int length, unsigned char *buffer
74 terminated by a 0 length
75 */
76
77 /* On call, digest->hashAlg is the desired hash algorithm */
78
TSS_HMAC_Generate(TPMT_HA * digest,const TPM2B_KEY * hmacKey,...)79 TPM_RC TSS_HMAC_Generate(TPMT_HA *digest, /* largest size of a digest */
80 const TPM2B_KEY *hmacKey,
81 ...)
82 {
83 TPM_RC rc = 0;
84 va_list ap;
85
86 va_start(ap, hmacKey);
87 rc = TSS_HMAC_Generate_valist(digest, hmacKey, ap);
88 va_end(ap);
89 return rc;
90 }
91
92 /* TSS_HMAC_Verify() can be called directly to check the HMAC of a list of streams.
93
94 The ... arguments are a list of the form
95 int length, unsigned char *buffer
96 terminated by a 0 length
97
98 */
99
TSS_HMAC_Verify(TPMT_HA * expect,const TPM2B_KEY * hmacKey,uint32_t sizeInBytes,...)100 TPM_RC TSS_HMAC_Verify(TPMT_HA *expect,
101 const TPM2B_KEY *hmacKey,
102 uint32_t sizeInBytes,
103 ...)
104 {
105 TPM_RC rc = 0;
106 int irc;
107 va_list ap;
108 TPMT_HA actual;
109
110 actual.hashAlg = expect->hashAlg; /* algorithm for the HMAC calculation */
111 va_start(ap, sizeInBytes);
112 if (rc == 0) {
113 rc = TSS_HMAC_Generate_valist(&actual, hmacKey, ap);
114 }
115 if (rc == 0) {
116 irc = memcmp((uint8_t *)&expect->digest, &actual.digest, sizeInBytes);
117 if (irc != 0) {
118 TSS_PrintAll("TSS_HMAC_Verify: calculated HMAC",
119 (uint8_t *)&actual.digest, sizeInBytes);
120 rc = TSS_RC_HMAC_VERIFY;
121 }
122 }
123 va_end(ap);
124 return rc;
125 }
126
127 /* TSS_KDFA() 11.4.9 Key Derivation Function
128
129 As defined in SP800-108, the inner loop for building the key stream is:
130
131 K(i) = HMAC (KI , [i]2 || Label || 00 || Context || [L]2)
132 */
133
TSS_KDFA(uint8_t * keyStream,TPM_ALG_ID hashAlg,const TPM2B * key,const char * label,const TPM2B * contextU,const TPM2B * contextV,uint32_t sizeInBits)134 TPM_RC TSS_KDFA(uint8_t *keyStream, /* OUT: key buffer */
135 TPM_ALG_ID hashAlg, /* IN: hash algorithm used in HMAC */
136 const TPM2B *key, /* IN: HMAC key */
137 const char *label, /* IN: KDFa label, NUL terminated */
138 const TPM2B *contextU, /* IN: context U */
139 const TPM2B *contextV, /* IN: context V */
140 uint32_t sizeInBits) /* IN: size of generated key in bits */
141
142 {
143 TPM_RC rc = 0;
144 uint32_t bytes = ((sizeInBits + 7) / 8); /* bytes left to produce */
145 uint8_t *stream;
146 uint32_t sizeInBitsNbo = htonl(sizeInBits); /* KDFa L2 */
147 uint16_t bytesThisPass; /* in one HMAC operation */
148 uint32_t counter; /* counter value */
149 uint32_t counterNbo; /* counter in big endian */
150 TPMT_HA hmac; /* hmac result for this pass */
151
152
153 if (rc == 0) {
154 hmac.hashAlg = hashAlg; /* for TSS_HMAC_Generate() */
155 bytesThisPass = TSS_GetDigestSize(hashAlg); /* start with hashAlg sized chunks */
156 if (bytesThisPass == 0) {
157 if (tssVerbose) printf("TSS_KDFA: KDFa failed\n");
158 rc = TSS_RC_KDFA_FAILED;
159 }
160 }
161 /* Generate required bytes */
162 for (stream = keyStream, counter = 1 ; /* beginning of stream, KDFa counter starts at 1 */
163 (rc == 0) && bytes > 0 ; /* bytes left to produce */
164 stream += bytesThisPass, bytes -= bytesThisPass, counter++) {
165
166 /* last pass, can be less than hashAlg sized chunks */
167 if (bytes < bytesThisPass) {
168 bytesThisPass = bytes;
169 }
170 counterNbo = htonl(counter); /* counter for this pass in BE format */
171
172 rc = TSS_HMAC_Generate(&hmac, /* largest size of an HMAC */
173 (const TPM2B_KEY *)key,
174 sizeof(uint32_t), &counterNbo, /* KDFa i2 counter */
175 strlen(label) + 1, label, /* KDFa label, use NUL as the KDFa
176 00 byte */
177 contextU->size, contextU->buffer, /* KDFa Context */
178 contextV->size, contextV->buffer, /* KDFa Context */
179 sizeof(uint32_t), &sizeInBitsNbo, /* KDFa L2 */
180 0, NULL);
181 memcpy(stream, &hmac.digest.tssmax, bytesThisPass);
182 }
183 return rc;
184 }
185
186 /* TSS_KDFE() 11.4.9.3 Key Derivation Function for ECDH
187
188 Digest = Hash(counter || Z || Use || PartyUInfo || PartyVInfo || bits )
189
190 where
191
192 counter is initialized to 1 and incremented for each iteration
193
194 Z is the X-coordinate of the product of a public (TPM) ECC key and
195 a different private ECC key
196
197 Use is a NULL-terminated string that indicates the use of the key
198 ("DUPLICATE", "IDENTITY", "SECRET", etc)
199
200 PartyUInfo is the X-coordinate of the public point of an ephemeral key
201
202 PartyVInfo is the X-coordinate of the public point of the TPM key
203
204 bits is a 32-bit value indicating the number of bits to be returned
205 */
206
TSS_KDFE(uint8_t * keyStream,TPM_ALG_ID hashAlg,const TPM2B * key,const char * label,const TPM2B * contextU,const TPM2B * contextV,uint32_t sizeInBits)207 TPM_RC TSS_KDFE(uint8_t *keyStream, /* OUT: key buffer */
208 TPM_ALG_ID hashAlg, /* IN: hash algorithm used */
209 const TPM2B *key, /* IN: Z */
210 const char *label, /* IN: KDFe label, NUL terminated */
211 const TPM2B *contextU, /* IN: context U */
212 const TPM2B *contextV, /* IN: context V */
213 uint32_t sizeInBits) /* IN: size of generated key in bits */
214
215 {
216 TPM_RC rc = 0;
217 uint32_t bytes = ((sizeInBits + 7) / 8); /* bytes left to produce */
218 uint8_t *stream;
219 uint16_t bytesThisPass; /* in one Hash operation */
220 uint32_t counter; /* counter value */
221 uint32_t counterNbo; /* counter in big endian */
222 TPMT_HA digest; /* result for this pass */
223
224 if (rc == 0) {
225 digest.hashAlg = hashAlg; /* for TSS_Hash_Generate() */
226 bytesThisPass = TSS_GetDigestSize(hashAlg); /* start with hashAlg sized chunks */
227 if (bytesThisPass == 0) {
228 if (tssVerbose) printf("TSS_KDFE: KDFe failed\n");
229 rc = TSS_RC_KDFE_FAILED;
230 }
231 }
232 /* Generate required bytes */
233 for (stream = keyStream, counter = 1 ; /* beginning of stream, KDFe counter starts at 1 */
234 (rc == 0) && bytes > 0 ; /* bytes left to produce */
235 stream += bytesThisPass, bytes -= bytesThisPass, counter++) {
236 /* last pass, can be less than hashAlg sized chunks */
237 if (bytes < bytesThisPass) {
238 bytesThisPass = bytes;
239 }
240 counterNbo = htonl(counter); /* counter for this pass in BE format */
241
242 rc = TSS_Hash_Generate(&digest, /* largest size of a digest */
243 sizeof(uint32_t), &counterNbo, /* KDFe i2 counter */
244 key->size, key->buffer,
245 strlen(label) + 1, label, /* KDFe label, use NUL as the KDFe
246 00 byte */
247 contextU->size, contextU->buffer, /* KDFe Context */
248 contextV->size, contextV->buffer, /* KDFe Context */
249 0, NULL);
250 memcpy(stream, &digest.digest.tssmax, bytesThisPass);
251 }
252 return rc;
253 }
254
255 /* On call, digest->hashAlg is the desired hash algorithm
256
257 ... is a list of int length, unsigned char *buffer pairs.
258
259 length 0 is ignored, buffer NULL terminates list.
260 */
261
TSS_Hash_Generate(TPMT_HA * digest,...)262 TPM_RC TSS_Hash_Generate(TPMT_HA *digest, /* largest size of a digest */
263 ...)
264 {
265 TPM_RC rc = 0;
266 va_list ap;
267 va_start(ap, digest);
268 rc = TSS_Hash_Generate_valist(digest, ap);
269 va_end(ap);
270 return rc;
271 }
272
273
274 /* TSS_GetDigestBlockSize() returns the digest block size in bytes based on the hash algorithm.
275
276 Returns 0 for an unknown algorithm.
277 */
278
279 /* NOTE: Marked as const function in header */
280
TSS_GetDigestBlockSize(TPM_ALG_ID hashAlg)281 uint16_t TSS_GetDigestBlockSize(TPM_ALG_ID hashAlg)
282 {
283 uint16_t size;
284
285 switch (hashAlg) {
286 #ifdef TPM_ALG_SHA1
287 case TPM_ALG_SHA1:
288 size = SHA1_BLOCK_SIZE;
289 break;
290 #endif
291 #ifdef TPM_ALG_SHA256
292 case TPM_ALG_SHA256:
293 size = SHA256_BLOCK_SIZE;
294 break;
295 #endif
296 #ifdef TPM_ALG_SHA384
297 case TPM_ALG_SHA384:
298 size = SHA384_BLOCK_SIZE;
299 break;
300 #endif
301 #ifdef TPM_ALG_SHA512
302 case TPM_ALG_SHA512:
303 size = SHA512_BLOCK_SIZE;
304 break;
305 #endif
306 #if 0
307 case TPM_ALG_SM3_256:
308 size = SM3_256_BLOCK_SIZE;
309 break;
310 #endif
311 default:
312 size = 0;
313 }
314 return size;
315 }
316
317 /* TPM_MGF1() generates an MGF1 'array' of length 'arrayLen' from 'seed' of length 'seedlen'
318
319 The openSSL DLL doesn't export MGF1 in Windows or Linux 1.0.0, so this version is created from
320 scratch.
321
322 Algorithm and comments (not the code) from:
323
324 PKCS #1: RSA Cryptography Specifications Version 2.1 B.2.1 MGF1
325
326 Prototype designed to be compatible with openSSL
327
328 MGF1 is a Mask Generation Function based on a hash function.
329
330 MGF1 (mgfSeed, maskLen)
331
332 Options:
333
334 Hash hash function (hLen denotes the length in octets of the hash
335 function output)
336
337 Input:
338
339 mgfSeed seed from which mask is generated, an octet string
340 maskLen intended length in octets of the mask, at most 2^32(hLen)
341
342 Output:
343 mask mask, an octet string of length l; or "mask too long"
344
345 Error: "mask too long'
346 */
347
TSS_MGF1(unsigned char * mask,uint32_t maskLen,const unsigned char * mgfSeed,uint16_t mgfSeedlen,TPMI_ALG_HASH halg)348 static TPM_RC TSS_MGF1(unsigned char *mask,
349 uint32_t maskLen,
350 const unsigned char *mgfSeed,
351 uint16_t mgfSeedlen,
352 TPMI_ALG_HASH halg)
353 {
354 TPM_RC rc = 0;
355 unsigned char counter[4]; /* 4 octets */
356 uint32_t count; /* counter as an integral type */
357 uint32_t outLen;
358 TPMT_HA digest;
359 uint16_t digestSize = TSS_GetDigestSize(halg);
360
361 digest.hashAlg = halg;
362
363 #if 0
364 if (rc == 0) {
365 /* this is possible with arrayLen on a 64 bit architecture, comment to quiet beam */
366 if ((maskLen / TPM_DIGEST_SIZE) > 0xffffffff) { /* constant condition */
367 if (tssVerbose)
368 printf("TSS_MGF1: Error (fatal), Output length too large for 32 bit counter\n");
369 rc = TPM_FAIL; /* should never occur */
370 }
371 }
372 #endif
373 /* 1.If l > 2^32(hLen), output "mask too long" and stop. */
374 /* NOTE Checked by caller */
375 /* 2. Let T be the empty octet string. */
376 /* 3. For counter from 0 to [masklen/hLen] - 1, do the following: */
377 for (count = 0, outLen = 0 ; (rc == 0) && (outLen < maskLen) ; count++) {
378 /* a. Convert counter to an octet string C of length 4 octets - see Section 4.1 */
379 /* C = I2OSP(counter, 4) NOTE Basically big endian */
380 uint32_t count_n = htonl(count);
381 memcpy(counter, &count_n, 4);
382 /* b.Concatenate the hash of the seed mgfSeed and C to the octet string T: */
383 /* T = T || Hash (mgfSeed || C) */
384 /* If the entire digest is needed for the mask */
385 if ((outLen + digestSize) < maskLen) {
386 rc = TSS_Hash_Generate(&digest,
387 mgfSeedlen, mgfSeed,
388 4, counter,
389 0, NULL);
390 memcpy(mask + outLen, &digest.digest, digestSize);
391 outLen += digestSize;
392 }
393 /* if the mask is not modulo TPM_DIGEST_SIZE, only part of the final digest is needed */
394 else {
395 /* hash to a temporary digest variable */
396 rc = TSS_Hash_Generate(&digest,
397 mgfSeedlen, mgfSeed,
398 4, counter,
399 0, NULL);
400 /* copy what's needed */
401 memcpy(mask + outLen, &digest.digest, maskLen - outLen);
402 outLen = maskLen; /* outLen = outLen + maskLen - outLen */
403 }
404 }
405 /* 4.Output the leading l octets of T as the octet string mask. */
406 return rc;
407 }
408
409 /*
410 OAEP Padding
411 */
412
413 /* TSS_RSA_padding_add_PKCS1_OAEP() is a variation of the the openSSL function
414
415 int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
416 unsigned char *f, int fl, unsigned char *p, int pl);
417
418 It is used because the openssl function is hard coded to SHA1.
419
420 This function was independently written from the PKCS1 specification "9.1.1.1 Encoding
421 Operation" and PKCS#1 v2.2, intended to be unencumbered by any license.
422
423
424 | <- emLen -> |
425
426 | lHash | PS | 01 | Message |
427
428 SHA flen
429
430 | db |
431 | dbMask |
432 | seed |
433
434 SHA
435
436 | seedMask |
437 | 00 | maskSeed | maskedDB |
438 */
439
TSS_RSA_padding_add_PKCS1_OAEP(unsigned char * em,uint32_t emLen,const unsigned char * from,uint32_t fLen,const unsigned char * p,int plen,TPMI_ALG_HASH halg)440 TPM_RC TSS_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen,
441 const unsigned char *from, uint32_t fLen,
442 const unsigned char *p,
443 int plen,
444 TPMI_ALG_HASH halg)
445 {
446 TPM_RC rc = 0;
447 TPMT_HA lHash;
448 unsigned char *db = NULL; /* compiler false positive */
449
450 unsigned char *dbMask = NULL; /* freed @1 */
451 unsigned char *seed = NULL; /* freed @2 */
452 unsigned char *maskedDb;
453 unsigned char *seedMask = NULL; /* compiler false positive */
454 unsigned char *maskedSeed;
455
456 uint16_t hlen = TSS_GetDigestSize(halg);
457
458 /* 1.a. If the length of L is greater than the input limitation for */
459 /* the hash function (2^61-1 octets for SHA-1) then output "parameter */
460 /* string too long" and stop. */
461 if (rc == 0) {
462 if (plen > 0xffff) {
463 if (tssVerbose) printf("TSS_RSA_padding_add_PKCS1_OAEP: Error, "
464 "label %u too long\n", plen);
465 rc = TSS_RC_RSA_PADDING;
466 }
467 }
468 /* 1.b. If ||M|| > emLen-2hLen-1 then output "message too long" and stop. */
469 if (rc == 0) {
470 if (emLen < ((2 * hlen) + 2 + fLen)) {
471 if (tssVerbose) printf("TSS_RSA_padding_add_PKCS1_OAEP: Error, "
472 "message length %u too large for encoded length %u\n",
473 fLen, emLen);
474 rc = TSS_RC_RSA_PADDING;
475 }
476 }
477 /* 2.a. Let lHash = Hash(L), an octet string of length hLen. */
478 if (rc == 0) {
479 lHash.hashAlg = halg;
480 rc = TSS_Hash_Generate(&lHash,
481 plen, p,
482 0, NULL);
483 }
484 if (rc == 0) {
485 /* 2.b. Generate an octet string PS consisting of emLen-||M||-2hLen-2 zero octets. The
486 length of PS may be 0. */
487 /* 2.c. Concatenate lHash, PS, a single octet of 0x01 the message M, to form a data block DB
488 as: DB = lHash || PS || 01 || M */
489 /* NOTE Since db is eventually maskedDb, part of em, create directly in em */
490 db = em + hlen + 1;
491 memcpy(db, &lHash.digest, hlen); /* lHash */
492 /* PSlen = emlen - flen - (2 * hlen) - 2 */
493 memset(db + hlen, 0, /* PS */
494 emLen - fLen - (2 * hlen) - 2);
495 /* position of 0x01 in db is
496 hlen + PSlen =
497 hlen + emlen - flen - (2 * hlen) - 2 =
498 emlen - hlen - flen - 2 */
499 db[emLen - fLen - hlen - 2] = 0x01;
500 memcpy(db + emLen - fLen - hlen - 1, from, fLen); /* M */
501 }
502 /* 2.d. Generate a random octet string seed of length hLen. */
503 if (rc == 0) {
504 rc = TSS_Malloc(&seed, hlen);
505 }
506 if (rc == 0) {
507 rc = TSS_RandBytes(seed, hlen);
508 }
509 if (rc == 0) {
510 rc = TSS_Malloc(&dbMask, emLen - hlen - 1);
511 }
512 if (rc == 0) {
513 /* 2.e. Let dbMask = MGF(seed, emLen-hLen-1). */
514 rc = TSS_MGF1(dbMask, emLen - hlen -1, /* dbLen */
515 seed, hlen,
516 halg);
517 }
518 if (rc == 0) {
519 /* 2.f. Let maskedDB = DB xor dbMask. */
520 /* NOTE Since maskedDB is eventually em, XOR directly to em */
521 maskedDb = em + hlen + 1;
522 TSS_XOR(maskedDb, db, dbMask, emLen - hlen -1);
523 /* 2.g. Let seedMask = MGF(maskedDB, hLen). */
524 /* NOTE Since seedMask is eventually em, create directly to em */
525 seedMask = em + 1;
526 rc = TSS_MGF1(seedMask, hlen,
527 maskedDb, emLen - hlen - 1,
528 halg);
529 }
530 if (rc == 0) {
531 /* 2.h. Let maskedSeed = seed xor seedMask. */
532 /* NOTE Since maskedSeed is eventually em, create directly to em */
533 maskedSeed = em + 1;
534 TSS_XOR(maskedSeed, seed, seedMask, hlen);
535 /* 2.i. 0x00, maskedSeed, and maskedDb to form EM */
536 /* NOTE Created directly in em */
537 }
538 free(dbMask); /* @1 */
539 free(seed); /* @2 */
540 return rc;
541 }
542
543 /* TPM_XOR XOR's 'in1' and 'in2' of 'length', putting the result in 'out'
544
545 */
546
TSS_XOR(unsigned char * out,const unsigned char * in1,const unsigned char * in2,size_t length)547 void TSS_XOR(unsigned char *out,
548 const unsigned char *in1,
549 const unsigned char *in2,
550 size_t length)
551 {
552 size_t i;
553
554 for (i = 0 ; i < length ; i++) {
555 out[i] = in1[i] ^ in2[i];
556 }
557 return;
558 }
559
560 /*
561 AES
562 */
563
564 #define TSS_AES_KEY_BITS 128
565
566 /* TSS_Sym_GetBlockSize() returns the block size for the symmetric algorithm. Returns 0 on for an
567 unknown algorithm.
568 */
569
570 /* NOTE: Marked as const function in header */
571
TSS_Sym_GetBlockSize(TPM_ALG_ID symmetricAlg,uint16_t keySizeInBits)572 uint16_t TSS_Sym_GetBlockSize(TPM_ALG_ID symmetricAlg,
573 uint16_t keySizeInBits)
574 {
575 keySizeInBits = keySizeInBits;
576
577 switch (symmetricAlg) {
578 #ifdef TPM_ALG_AES
579 case TPM_ALG_AES:
580 #endif
581 #ifdef TPM_ALG_SM4 /* Both AES and SM4 use the same block size */
582 case TPM_ALG_SM4:
583 #endif
584 return 16;
585 default:
586 return 0;
587 }
588 return 0;
589 }
590
591