2121#include "tpm2_nv_util.h"
2222#include "tpm2_tool.h"
2323#if OPENSSL_VERSION_NUMBER >= 0x30000000L
24- #include <openssl/core_names.h>
24+ #include <openssl/core_names.h>
2525#endif
2626
2727
@@ -1073,7 +1073,7 @@ static tool_rc get_nv_ek_certificate(ESYS_CONTEXT *ectx) {
10731073
10741074 tool_rc rc = tool_rc_success ;
10751075
1076- for (i = 0 ; i < ARRAY_LEN (ek_index_maps ); i ++ ) {
1076+ for (i = 0 ; i < ARRAY_LEN (ek_index_maps ); i ++ ) {
10771077 if (ek_index_maps [i ].found ) {
10781078 rc = nv_read (ectx , ek_index_maps [i ].index );
10791079 if (rc != tool_rc_success ) {
@@ -1165,33 +1165,89 @@ static tool_rc process_input(ESYS_CONTEXT *ectx) {
11651165 return print_intel_ek_certificate_warning ();
11661166}
11671167
1168- static char * base64_decode ( char * * split , unsigned int cert_length ) {
1168+ static const char * get_json_field ( const char * cert_buffer , const char * field_name ) {
11691169
1170- * split += strlen ("certficate\" : " );
1171- char * final_string = NULL ;
1172- int outlen ;
1173- CURL * curl = curl_easy_init ();
1174- if (curl ) {
1175- char * output = curl_easy_unescape (curl , * split , cert_length , & outlen );
1176- if (output ) {
1177- final_string = strdup (output );
1178- curl_free (output );
1179- }
1170+ const char * field_ptr = strstr (cert_buffer , field_name );
1171+ if (!field_ptr ) {
1172+ return NULL ;
11801173 }
1181- curl_easy_cleanup (curl );
1182- curl_global_cleanup ();
1174+ field_ptr += strlen (field_name );
1175+
1176+ // Skip spaces after field name
1177+ while (field_ptr && * field_ptr == ' ' )
1178+ ++ field_ptr ;
1179+
1180+ // Expect colon after field name
1181+ if (* field_ptr != ':' )
1182+ return NULL ;
1183+ ++ field_ptr ;
1184+
1185+ // Skip spaces after colon
1186+ while (field_ptr && * field_ptr == ' ' )
1187+ ++ field_ptr ;
1188+
1189+ // Expect double quote after colon
1190+ if (* field_ptr != '"' )
1191+ return NULL ;
1192+ ++ field_ptr ;
1193+
1194+ return field_ptr ;
1195+ }
11831196
1184- if (final_string ) {
1185- size_t i ;
1186- for (i = 0 ; i < strlen (final_string ); i ++ ) {
1187- final_string [i ] = final_string [i ] == '-' ? '+' : final_string [i ];
1188- final_string [i ] = final_string [i ] == '_' ? '/' : final_string [i ];
1189- final_string [i ] = final_string [i ] == '"' ? '\0' : final_string [i ];
1190- final_string [i ] = final_string [i ] == '}' ? '\0' : final_string [i ];
1197+ static int hex_digit (unsigned char c ) {
1198+ if (c >= '0' && c <= '9' ) return c - '0' ;
1199+ if (c >= 'a' && c <= 'f' ) return c - 'a' + 10 ;
1200+ if (c >= 'A' && c <= 'F' ) return c - 'A' + 10 ;
1201+ return -1 ;
1202+ }
1203+
1204+ static char * convert_base64url_to_base64 (const char * s ) {
1205+
1206+ size_t len = strlen (s );
1207+ char * out = malloc (len + 1 );
1208+ if (!out ) {
1209+ return NULL ;
1210+ }
1211+
1212+ size_t i = 0 ;
1213+ size_t j = 0 ;
1214+ while (i < len ) {
1215+ switch (s [i ]) {
1216+ case '-' :
1217+ out [j ] = '+' ;
1218+ i ++ ;
1219+ break ;
1220+ case '_' :
1221+ out [j ] = '/' ;
1222+ i ++ ;
1223+ break ;
1224+ case '"' :
1225+ case '}' :
1226+ out [j ] = '\0' ;
1227+ return out ;
1228+ case '%' :
1229+ if (i + 2 < len ) {
1230+ int hi = hex_digit (s [i + 1 ]);
1231+ int lo = hex_digit (s [i + 2 ]);
1232+ if (hi >= 0 && lo >= 0 ) {
1233+ out [j ] = (char )((hi << 4 ) | lo );
1234+ i += 3 ;
1235+ break ;
1236+ }
1237+ }
1238+ out [j ] = s [i ];
1239+ i ++ ;
1240+ break ;
1241+ default :
1242+ out [j ] = s [i ];
1243+ i ++ ;
1244+ break ;
11911245 }
1246+ j ++ ;
11921247 }
11931248
1194- return final_string ;
1249+ out [j ] = '\0' ;
1250+ return out ;
11951251}
11961252
11971253#define PEM_BEGIN_CERT_LINE "\n-----BEGIN CERTIFICATE-----\n"
@@ -1207,8 +1263,10 @@ static tool_rc process_output(void) {
12071263 bool is_intel_cert = ctx .manufacturer == VENDOR_INTEL ;
12081264
12091265 if (!is_intel_cert && ctx .web_cert_buffer ) {
1210- is_intel_cert = !(strncmp ((const char * )ctx .web_cert_buffer ,
1211- "{\"pubhash" , strlen ("{\"pubhash" )));
1266+ /*
1267+ * Heuristics: If the cert contains the "pubhash" field, it is likely an Intel cert.
1268+ */
1269+ is_intel_cert = (bool )get_json_field ((const char * )ctx .web_cert_buffer , "\"pubhash\"" );
12121270 }
12131271
12141272 /*
@@ -1223,12 +1281,12 @@ static tool_rc process_output(void) {
12231281 * Base 64: https://tools.ietf.org/html/rfc4648#section-5 to PEM
12241282 */
12251283 if (ctx .web_cert_buffer && is_intel_cert && !ctx .is_cert_raw ) {
1226- char * split = strstr (( char * )ctx .web_cert_buffer , "certificate" );
1227- if (!split ) {
1284+ const char * cert_field = get_json_field (( const char * )ctx .web_cert_buffer , "\" certificate\" " );
1285+ if (!cert_field ) {
12281286 LOG_ERR ("Unexpected EK cert response: missing \"certificate\" field" );
12291287 return tool_rc_general_error ;
12301288 }
1231- char * copy_buffer = base64_decode ( & split , ctx . web_cert_buffer_size );
1289+ char * copy_buffer = convert_base64url_to_base64 ( cert_field );
12321290 if (!copy_buffer ) {
12331291 LOG_ERR ("Failed to decode EK certificate data" );
12341292 return tool_rc_general_error ;
@@ -1253,6 +1311,7 @@ static tool_rc process_output(void) {
12531311 copy_buffer );
12541312 strcpy ((char * )ctx .web_cert_buffer + strlen (PEM_BEGIN_CERT_LINE ) +
12551313 strlen (copy_buffer ), PEM_END_CERT_LINE );
1314+ ctx .web_cert_buffer_size = strlen ((char * )ctx .web_cert_buffer );
12561315 free (copy_buffer );
12571316 }
12581317
@@ -1312,7 +1371,7 @@ static tool_rc process_output(void) {
13121371 LOG_WARN ("Ignoring the additional output file since only %zu certificates found on NV" ,
13131372 ctx .nv_cert_count );
13141373 }
1315-
1374+
13161375 return tool_rc_success ;
13171376}
13181377
@@ -1379,7 +1438,7 @@ static bool on_option(char key, char *value) {
13791438 if (!value || !value [0 ]) {
13801439 LOG_ERR ("No encoding given." );
13811440 return false;
1382- }
1441+ }
13831442 switch (value [0 ]) {
13841443 case 'a' :
13851444 ctx .encoding = ENC_AMD ;
0 commit comments