Utility to Import external RSA pem key into TPM
[aaf/sshsm.git] / TPM2-Plugin / lib / tpm2_hash.c
1 //**********************************************************************;
2 // Copyright (c) 2017, Intel Corporation
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of Intel Corporation nor the names of its contributors
16 // may be used to endorse or promote products derived from this software without
17 // specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29 // THE POSSIBILITY OF SUCH DAMAGE.
30 //**********************************************************************;
31 #include <errno.h>
32 #include <string.h>
33
34 #include <tss2/tss2_sys.h>
35
36 #include "log.h"
37 #include "files.h"
38 #include "tpm2_hash.h"
39 #include "tpm2_util.h"
40
41 bool tpm2_hash_compute_data(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH halg,
42         TPMI_RH_HIERARCHY hierarchy, BYTE *buffer, UINT16 length,
43         TPM2B_DIGEST *result, TPMT_TK_HASHCHECK *validation) {
44
45     FILE *mem = fmemopen(buffer, length, "rb");
46     if (!mem) {
47         LOG_ERR("Error converting buffer to memory stream: %s",
48                 strerror(errno));
49         return false;
50     }
51
52     return tpm2_hash_file(sapi_context, halg, hierarchy, mem, result, validation);
53 }
54
55 bool tpm2_hash_file(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH halg,
56         TPMI_RH_HIERARCHY hierarchy, FILE *input, TPM2B_DIGEST *result,
57         TPMT_TK_HASHCHECK *validation) {
58
59     TPM2B_AUTH nullAuth = TPM2B_EMPTY_INIT;
60     TPMI_DH_OBJECT sequenceHandle;
61
62     TSS2L_SYS_AUTH_COMMAND cmdAuthArray = { 1, {{.sessionHandle = TPM2_RS_PW, 
63             .nonce = TPM2B_EMPTY_INIT, .hmac = TPM2B_EMPTY_INIT,
64             .sessionAttributes = 0, }}};
65     unsigned long file_size = 0;
66
67     /* Suppress error reporting with NULL path */
68     bool res = files_get_file_size(input, &file_size, NULL);
69
70     /* If we can get the file size and its less than 1024, just do it in one hash invocation */
71     if (res && file_size <= TPM2_MAX_DIGEST_BUFFER) {
72
73         TPM2B_MAX_BUFFER buffer = { .size = file_size };
74
75         res = files_read_bytes(input, buffer.buffer, buffer.size);
76         if (!res) {
77             LOG_ERR("Error reading input file!");
78             return false;
79         }
80
81         TSS2_RC rval = TSS2_RETRY_EXP(Tss2_Sys_Hash(sapi_context, NULL, &buffer, halg,
82             hierarchy, result, validation, NULL));
83         if (rval != TSS2_RC_SUCCESS) {
84             LOG_PERR(Tss2_Sys_Hash, rval);
85             return false;
86         }
87
88         return true;
89     }
90
91     /*
92      * Size is either unkown because the FILE * is a fifo, or it's too big
93      * to do in a single hash call. Based on the size figure out the chunks
94      * to loop over, if possible. This way we can call Complete with data.
95      */
96     TSS2_RC rval = TSS2_RETRY_EXP(Tss2_Sys_HashSequenceStart(sapi_context, NULL, &nullAuth,
97             halg, &sequenceHandle, NULL));
98     if (rval != TPM2_RC_SUCCESS) {
99         LOG_PERR(Tss2_Sys_HashSequenceStart, rval);
100         return rval;
101     }
102
103     /* If we know the file size, we decrement the amount read and terminate the loop
104      * when 1 block is left, else we go till feof.
105      */
106     size_t left = file_size;
107     bool use_left = !!res;
108
109     TPM2B_MAX_BUFFER data;
110
111     bool done = false;
112     while (!done) {
113
114         size_t bytes_read = fread(data.buffer, 1,
115                 BUFFER_SIZE(typeof(data), buffer), input);
116         if (ferror(input)) {
117             LOG_ERR("Error reading from input file");
118             return false;
119         }
120
121         data.size = bytes_read;
122
123         /* if data was read, update the sequence */
124         rval = TSS2_RETRY_EXP(Tss2_Sys_SequenceUpdate(sapi_context, sequenceHandle,
125                 &cmdAuthArray, &data, NULL));
126         if (rval != TPM2_RC_SUCCESS) {
127             LOG_PERR(Tss2_Sys_SequenceUpdate, rval);
128             return false;
129         }
130
131         if (use_left) {
132             left -= bytes_read;
133             if (left <= TPM2_MAX_DIGEST_BUFFER) {
134                 done = true;
135                 continue;
136             }
137         } else if (feof(input)) {
138             done = true;
139         }
140     } /* end file read/hash update loop */
141
142     if (use_left) {
143         data.size = left;
144         bool res = files_read_bytes(input, data.buffer, left);
145         if (!res) {
146             LOG_ERR("Error reading from input file.");
147             return false;
148         }
149     } else {
150         data.size = 0;
151     }
152
153     rval = TSS2_RETRY_EXP(Tss2_Sys_SequenceComplete(sapi_context, sequenceHandle,
154             &cmdAuthArray, &data, hierarchy, result, validation,
155             NULL));
156     if (rval != TSS2_RC_SUCCESS) {
157         LOG_PERR(Tss2_Sys_SequenceComplete, rval);
158         return false;
159     }
160
161     return true;
162 }