• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 
3 #ifdef HAVE_CONFIG_H
4 #include <config.h>
5 #endif
6 
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <curl/curl.h>
13 #include <openssl/buffer.h>
14 #include <openssl/evp.h>
15 #include <openssl/sha.h>
16 #include <json-c/json.h>
17 
18 #include "fapi_crypto.h"
19 #include "ifapi_helpers.h"
20 
21 #define LOGMODULE fapi
22 #include "util/log.h"
23 #include "util/aux_util.h"
24 
25 typedef struct tpm_getekcertificate_ctx tpm_getekcertificate_ctx;
26 struct tpm_getekcertificate_ctx {
27     char *ec_cert_path;
28     FILE *ec_cert_file_handle;
29     char *ek_server_addr;
30     unsigned int SSL_NO_VERIFY;
31     char *ek_path;
32     bool verbose;
33     bool is_tpm2_device_active;
34     TPM2B_PUBLIC *out_public;
35 };
36 
37 static tpm_getekcertificate_ctx ctx = {
38     .is_tpm2_device_active = true,
39 };
40 
41 /** Compute the SHA256 hash from the public key of an EK.
42  *
43  * @param[in]  ek_public The public information of the EK.
44  * @retval unsigned_char* The hash value.
45  * @retval NULL If the computation of the hash fails.
46  */
hash_ek_public(TPM2B_PUBLIC * ek_public)47 static unsigned char *hash_ek_public(TPM2B_PUBLIC *ek_public) {
48 
49     unsigned char *hash = (unsigned char *)malloc(SHA256_DIGEST_LENGTH);
50     if (!hash) {
51         LOG_ERROR("OOM");
52         return NULL;
53     }
54 
55     SHA256_CTX sha256;
56     int is_success = SHA256_Init(&sha256);
57     if (!is_success) {
58         LOG_ERROR("SHA256_Init failed");
59         goto err;
60     }
61 
62     switch (ek_public->publicArea.type) {
63     case TPM2_ALG_RSA:
64         /* Add public key to the hash. */
65         is_success = SHA256_Update(&sha256,
66                                    ek_public->publicArea.unique.rsa.buffer,
67                                    ek_public->publicArea.unique.rsa.size);
68         if (!is_success) {
69             LOG_ERROR("SHA256_Update failed");
70             goto err;
71         }
72 
73         /* Add exponent to the hash. */
74         if (ek_public->publicArea.parameters.rsaDetail.exponent != 0) {
75             LOG_ERROR("non-default exponents unsupported");
76             goto err;
77         }
78         /* Exponent 65537 will be added. */
79         BYTE buf[3] = { 0x1, 0x00, 0x01 };
80         is_success = SHA256_Update(&sha256, buf, sizeof(buf));
81         if (!is_success) {
82             LOG_ERROR("SHA256_Update failed");
83             goto err;
84         }
85         break;
86 
87     case TPM2_ALG_ECC:
88         is_success = SHA256_Update(&sha256,
89                                    ek_public->publicArea.unique.ecc.x.buffer,
90                                    ek_public->publicArea.unique.ecc.x.size);
91         if (!is_success) {
92             LOG_ERROR("SHA256_Update failed");
93             goto err;
94         }
95 
96         /* Add public key to the hash. */
97         is_success = SHA256_Update(&sha256,
98                                    ek_public->publicArea.unique.ecc.y.buffer,
99                                    ek_public->publicArea.unique.ecc.y.size);
100         if (!is_success) {
101             LOG_ERROR("SHA256_Update failed");
102             goto err;
103         }
104         break;
105 
106     default:
107         LOG_ERROR("unsupported EK algorithm");
108         goto err;
109     }
110 
111     is_success = SHA256_Final(hash, &sha256);
112     if (!is_success) {
113         LOG_ERROR("SHA256_Final failed");
114         goto err;
115     }
116 
117     LOG_TRACE("public-key-hash:");
118     LOG_TRACE("  sha256: ");
119     LOGBLOB_TRACE(&hash[0], SHA256_DIGEST_LENGTH, "Hash");
120     return hash;
121 err:
122     free(hash);
123     return NULL;
124 }
125 
126 /** Calculate the base64 encoding of the hash of the Endorsement Public Key.
127  *
128  * @param[in] buffer The hash of the endorsement public key.
129  * @retval char* The base64 encoded string.
130  * @retval NULL if the encoding fails.
131  */
132 static char *
base64_encode(const unsigned char * buffer)133 base64_encode(const unsigned char* buffer)
134 {
135     BIO *bio, *b64;
136     BUF_MEM *buffer_pointer;
137 
138     LOG_INFO("Calculating the base64_encode of the hash of the Endorsement"
139              "Public Key:");
140 
141     if (buffer == NULL) {
142         LOG_ERROR("hash_ek_public returned null");
143         return NULL;
144     }
145 
146     b64 = BIO_new(BIO_f_base64());
147     bio = BIO_new(BIO_s_mem());
148     bio = BIO_push(b64, bio);
149     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
150     BIO_write(bio, buffer, SHA256_DIGEST_LENGTH);
151     (void)(BIO_flush(bio));
152     BIO_get_mem_ptr(bio, &buffer_pointer);
153 
154     /* these are not NULL terminated */
155     char *b64text = buffer_pointer->data;
156     size_t len = buffer_pointer->length;
157 
158     size_t i;
159     for (i = 0; i < len; i++) {
160         if (b64text[i] == '+') {
161             b64text[i] = '-';
162         }
163         if (b64text[i] == '/') {
164             b64text[i] = '_';
165         }
166     }
167 
168     char *final_string = NULL;
169 
170     CURL *curl = curl_easy_init();
171     if (curl) {
172         char *output = curl_easy_escape(curl, b64text, len);
173         if (output) {
174             final_string = strdup(output);
175             curl_free(output);
176         }
177     }
178     curl_easy_cleanup(curl);
179     curl_global_cleanup();
180     BIO_free_all(bio);
181 
182     /* format to a proper NULL terminated string */
183     return final_string;
184 }
185 
186 /** Decode a base64 encoded certificate into binary form.
187  *
188  * @param[in]  buffer The base64 encoded certificate.
189  * @param[in]  len The length of the encoded certificate.
190  * @param[out] new_len The lenght of the binary certificate.
191  * @retval char* The binary data of the certificate.
192  * @retval NULL if the decoding fails.
193  */
194 static char *
base64_decode(unsigned char * buffer,size_t len,size_t * new_len)195 base64_decode(unsigned char* buffer, size_t len, size_t *new_len)
196 {
197     size_t i, unescape_len, r;
198     char *binary_data = NULL, *unescaped_string = NULL;
199 
200     LOG_INFO("Decoding the base64 encoded cert into binary form");
201 
202     if (buffer == NULL) {
203         LOG_ERROR("Cert buffer is null");
204         return NULL;
205     }
206 
207     for (i = 0; i < len; i++) {
208         if (buffer[i] == '-') {
209             buffer[i] = '+';
210         }
211         if (buffer[i] == '_') {
212             buffer[i] = '/';
213         }
214     }
215 
216     CURL *curl = curl_easy_init();
217     if (curl) {
218         /* Convert URL encoded string to a "plain string" */
219         char *output = curl_easy_unescape(curl, (char *)buffer,
220                                           len, (int *)&unescape_len);
221         if (output) {
222             unescaped_string = strdup(output);
223             curl_free(output);
224         }
225     }
226     curl_easy_cleanup(curl);
227     curl_global_cleanup();
228     if (unescaped_string == NULL)
229         return NULL;
230 
231     binary_data = calloc(1, unescape_len);
232     if (binary_data == NULL) {
233         free (unescaped_string);
234         return NULL;
235     }
236 
237     BIO *bio, *b64;
238     bio = BIO_new_mem_buf(unescaped_string, -1);
239     b64 = BIO_new(BIO_f_base64());
240     bio = BIO_push(b64, bio);
241     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
242 
243     if ((r = BIO_read(bio, binary_data, unescape_len)) <= 0) {
244         LOG_ERROR("BIO_read base64 encoded cert failed");
245         free(binary_data);
246         binary_data = NULL;
247     }
248     *new_len = r;
249 
250     free (unescaped_string);
251     BIO_free_all(bio);
252     return binary_data;
253 }
254 
255 /** Get endorsement certificate from the WEB.
256  *
257  * The base64 encoded public endorsement key will be added to the INTEL
258  * server address and used as URL to retrieve the certificate.
259  * The certificate will be retrieved via curl.
260  *
261  * @param[in]  b64h The base64 encoded public key.
262  * @param[out] buffer The json encoded certificate.
263  * @param[out] cert_size The size of the certificate.
264  */
retrieve_endorsement_certificate(char * b64h,unsigned char ** buffer,size_t * cert_size)265 int retrieve_endorsement_certificate(char *b64h, unsigned char ** buffer,
266                                      size_t *cert_size) {
267     int ret = -1;
268 
269     size_t len = 1 + strlen(b64h) + strlen(ctx.ek_server_addr);
270     char *weblink = (char *) malloc(len);
271 
272     if (!weblink) {
273         LOG_ERROR("oom");
274         return ret;
275     }
276 
277     snprintf(weblink, len, "%s%s", ctx.ek_server_addr, b64h);
278 
279     CURLcode rc =  ifapi_get_curl_buffer((unsigned char *)weblink,
280                                          buffer, cert_size);
281     free(weblink);
282     return rc;
283 }
284 
285 /** Get INTEL certificate for EK
286  *
287  * Using the base64 encoded public endorsement key the JSON encoded certificate
288  * will be downloaded.
289  * The JSON certificate will be parsed and the base64 encoded certificate
290  * will be converted into binary format.
291  *
292  *
293  * @param[in] context The FAPI context with the configuration data.
294  * @param[in] ek_public The out public data of the EK.
295  * @param[out] cert_buffer the der encoded certificate.
296  * @param[out] cert_size The size of the certificate buffer.
297  *
298  * @retval TSS2_RC_SUCCESS on success.
299  * @retval TSS2_FAPI_RC_NO_CERT If an error did occur during certificate downloading.
300  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occured.
301  * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
302  */
303 TSS2_RC
ifapi_get_intl_ek_certificate(FAPI_CONTEXT * context,TPM2B_PUBLIC * ek_public,unsigned char ** cert_buffer,size_t * cert_size)304 ifapi_get_intl_ek_certificate(FAPI_CONTEXT *context, TPM2B_PUBLIC *ek_public,
305                               unsigned char ** cert_buffer, size_t *cert_size)
306 {
307     int rc = 1;
308     unsigned char *hash = hash_ek_public(ek_public);
309     char *cert_ptr;
310     char *cert_start = NULL, *cert_bin = NULL;
311     char *b64 = base64_encode(hash);
312 
313     if (!b64) {
314         LOG_ERROR("base64_encode returned null");
315         goto out;
316     }
317     if (context->config.intel_cert_service)
318         ctx.ek_server_addr = context->config.intel_cert_service;
319     else
320         ctx.ek_server_addr = "https://ekop.intel.com/ekcertservice/";
321 
322     LOG_INFO("%s", b64);
323 
324     /* Download the JSON encoded certificate. */
325     rc = retrieve_endorsement_certificate(b64, cert_buffer, cert_size);
326     free(b64);
327     goto_if_error(rc, "Retrieve endorsement certificate", out);
328     cert_ptr = (char *)*cert_buffer;
329     LOGBLOB_DEBUG((uint8_t *)cert_ptr, *cert_size, "%s", "Certificate");
330 
331     /* Parse certificate data out of the json structure */
332     struct json_object *jso_cert, *jso = json_tokener_parse(cert_ptr);
333     if (jso == NULL)
334         goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE,
335                    "Failed to parse EK cert data", out_free_json);
336 
337     if (!json_object_object_get_ex(jso, "certificate", &jso_cert))
338         goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE,
339                    "Could not find cert object", out_free_json);
340 
341     if (!json_object_is_type(jso_cert, json_type_string))
342         goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE,
343                    "Invalid EK cert data", out_free_json);
344 
345     cert_start = strdup(json_object_get_string(jso_cert));
346     if (!cert_start) {
347         SAFE_FREE(cert_ptr);
348         goto_error(rc, TSS2_FAPI_RC_MEMORY,
349                    "Failed to duplicate cert", out_free_json);
350     }
351 
352     *cert_size = strlen(cert_start);
353 
354     /* Base64 decode buffer into binary PEM format */
355     cert_bin = base64_decode((unsigned char *)cert_start,
356                              *cert_size, cert_size);
357     SAFE_FREE(cert_ptr);
358     SAFE_FREE(cert_start);
359 
360     if (cert_bin == NULL) {
361         goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE,
362                    "Invalid EK cert data", out_free_json);
363     }
364     LOG_DEBUG("Binary cert size %zu", *cert_size);
365     *cert_buffer = (unsigned char *)cert_bin;
366 
367 out_free_json:
368     json_object_put(jso);
369 
370 out:
371     /* In some case this call was necessary after curl usage */
372     OpenSSL_add_all_algorithms();
373 
374     free(hash);
375     if (rc == 0) {
376         return TSS2_RC_SUCCESS;
377     } else {
378         LOG_ERROR("Get INTEL EK certificate.");
379         return TSS2_FAPI_RC_NO_CERT;
380     }
381 }
382