/* * Copyright (C) 2011-2017 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "aesm_encode.h" #include "se_memcpy.h" #include "AEClass.h" #include "PVEClass.h" #include "tlv_common.h" #include #include #include #include #include #include "upse/helper.h" #include "upse/Buffer.h" /** * Method converts byte containing value from 0x00-0x0F into its corresponding ASCII code, * e.g. converts 0x00 to '0', 0x0A to 'A'. * Note: This is mainly a helper method for internal use in byte_array_to_hex_string(). * * @param in byte to be converted (allowed values: 0x00-0x0F) * * @return ASCII code representation of the byte or 0 if method failed (e.g input value was not in provided range). */ static uint8_t convert_value_to_ascii(uint8_t in) { if(in <= 0x09) { return (uint8_t)(in + '0'); } else if(in <= 0x0F) { return (uint8_t)(in - 10 + 'A'); } return 0; } /** * Method converts char containing ASCII code into its corresponding value, * e.g. converts '0' to 0x00, 'A' to 0x0A. * * @param in char containing ASCII code (allowed values: '0-9', 'a-f', 'A-F') * @param val output parameter containing converted value, if method succeeds. * * @return true if conversion succeeds, false otherwise */ static bool convert_ascii_to_value(uint8_t in, uint8_t& val) { if(in >= '0' && in <= '9') { val = static_cast(in - '0'); } else if(in >= 'A' && in <= 'F') { val = static_cast(in - 'A'+10); } else if(in >= 'a' && in <= 'f') { val = static_cast(in - 'a'+10); } else { return false; } return true; } //Function to do HEX encoding of array of bytes //@param in_buf, bytes array whose length is in_size // out_buf, output the HEX encoding of in_buf on success. //@return true on success and false on error //The out_size must always be 2*in_size since each byte into encoded by 2 characters static bool byte_array_to_hex_string(const uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) { if(in_size>UINT32_MAX/2)return false; if(in_buf==NULL||out_buf==NULL|| out_size!=in_size*2 )return false; for(uint32_t i=0; i< in_size; i++) { *out_buf++ = convert_value_to_ascii( static_cast(*in_buf >> 4)); *out_buf++ = convert_value_to_ascii( static_cast(*in_buf & 0xf)); in_buf++; } return true; } //Function to do HEX decoding //@param in_buf, character strings which are HEX encoding of a byte array // out_buf, output the decode byte array on success //@return true on success and false on error //The in_size must be even number and equals 2*out_size static bool hex_string_to_byte_array(const uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t out_size) { if(out_size>UINT32_MAX/2)return false; if(in_buf==NULL||out_buf==NULL||out_size*2!=in_size)return false; for(uint32_t i=0;i(value_second+ (value_first<<4)); } return true; } //Function to use openssl to do BASE64 encoding static bool base_64_encode(const uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t *out_size) { BIO* bioMem = NULL; bool ret = false; BIO *bio64 = NULL; bio64 = BIO_new(BIO_f_base64()); if(bio64 == NULL) goto ret_point; BIO_set_flags(bio64, BIO_FLAGS_BASE64_NO_NL); bioMem = BIO_new(BIO_s_mem()); if(bioMem == NULL) goto ret_point; (void)BIO_push(bio64, bioMem); if(BIO_write(bio64, in_buf, in_size) != (int)in_size){ goto ret_point; } (void)BIO_flush(bio64); BUF_MEM *bptr; BIO_get_mem_ptr(bio64, &bptr); if(bptr==NULL){ goto ret_point; } if(*out_size < bptr->length){ goto ret_point; } if(memcpy_s(out_buf, *out_size,bptr->data, bptr->length)!=0) goto ret_point; *out_size = static_cast(bptr->length); ret = true; ret_point: BIO_free_all(bio64);//we need not free bioMem too because the free_all has free it. return ret; } //Function to use openssl to do BASE64 decoding static bool base_64_decode(const uint8_t *in_buf, uint32_t in_size, uint8_t *out_buf, uint32_t *out_size) { BIO *b64 =NULL, *bmem = NULL; bool ret = false; int read=0; memset(out_buf, 0, *out_size); b64 = BIO_new(BIO_f_base64()); if(b64 == NULL) goto ret_point; BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bmem = BIO_new_mem_buf(const_cast(in_buf), in_size); if(bmem == NULL){ goto ret_point; } bmem = BIO_push(b64, bmem); read = BIO_read(bmem, out_buf, *out_size); if(read < 0) goto ret_point; *out_size = read; ret = true; ret_point: BIO_free_all(bmem); return ret; } //Function to give an upper bound of size of data after BASE64 decoding //@param length: the length in bytes of BASE64 encoded data //@return an upper bound of length in bytes of decoded data static uint32_t get_unbase_64_length(uint32_t length) { return (length * 3 / 4) + ((length * 3 % 4 > 0) ? 1 : 0 ); } //Function to give an upper bound of size of data after BASR64 encoding //@param length: the length in bytes of data to be encoded //@return an upper bound of length in bytes of data after encoding static uint32_t get_base_64_length_upbound(uint32_t length) { uint32_t extra = (length+9)/10+50;//using enough extra memory return extra+(length*4+2)/3; } uint32_t get_request_encoding_length(const uint8_t *req) { //adding 1 extra byte to hold '\0' return static_cast(2*PROVISION_REQUEST_HEADER_SIZE+get_base_64_length_upbound(GET_BODY_SIZE_FROM_PROVISION_REQUEST(req))+1); } uint32_t get_response_decoding_length(uint32_t buf_len) { if(buf_len<2*PROVISION_RESPONSE_HEADER_SIZE) return 0; return static_cast(get_unbase_64_length(buf_len-2*static_cast(PROVISION_RESPONSE_HEADER_SIZE)) + PROVISION_RESPONSE_HEADER_SIZE); } bool encode_request(const uint8_t *req, uint32_t req_len, uint8_t *out_buf, uint32_t *out_len) { uint32_t encoded_header_size = static_cast(2*PROVISION_REQUEST_HEADER_SIZE); if(*out_len(2*PROVISION_RESPONSE_HEADER_SIZE), resp, static_cast(PROVISION_RESPONSE_HEADER_SIZE))) return false; if(*out_len(PROVISION_RESPONSE_HEADER_SIZE); if(!base_64_decode(input_buf+static_cast(2*PROVISION_RESPONSE_HEADER_SIZE), input_len - static_cast(2*PROVISION_RESPONSE_HEADER_SIZE), resp+static_cast(PROVISION_RESPONSE_HEADER_SIZE), out_len)) return false; *out_len += static_cast(PROVISION_RESPONSE_HEADER_SIZE); if(*out_len != GET_SIZE_FROM_PROVISION_RESPONSE(resp)) return false; return true; } // // certPseSvn // // return ISVSVN of PSE stored in PSE certificate or 0, if error // // remarks // the ISVSVN in the cert could be old since it only updates when we execute // pse provisioning // uint32_t certPseSvn() { uint32_t pseSvn = 0; bool pseSvnFound = false; X509* cert = NULL; std::list certChain; X509_NAME* subj2 = NULL; X509_NAME* issuer2 = NULL; X509_NAME_ENTRY *entry = NULL; ASN1_STRING *entryData = NULL; char *str = NULL; // // load cert chain from disk // ae_error_t loadCertError = Helper::LoadCertificateChain(certChain); // // create openssl bio to temporarily hold cert data // BIO* certBio = BIO_new(BIO_s_mem()); if ((AE_SUCCESS == loadCertError) && (NULL != certBio)) { for (std::list::const_iterator iterator = certChain.begin(), end = certChain.end(); iterator != end; ++iterator) { // // go from binary (tempCert) to mem bio (certBio) to internal OpenSSL representation of x509 cert (cert) // const upse::Buffer& tempCert = *iterator; int retVal = BIO_write(certBio, (const char*) tempCert.getData(), tempCert.getSize()); if (retVal <= 0) break; cert = d2i_X509_bio(certBio, NULL); if (NULL == cert) { break; } // // PSE ISVSVN is in parent of the leaf cert, in name // we'll look for a cert with "Intel PSE" at the beginning of the subject name and // "Intel PSE TCB CA" at the beginning of the issuer name and then we'll get // the ISVSVN value from (later in) the issuer name // subj2 = X509_get_subject_name(cert); issuer2 = X509_get_issuer_name(cert); for (int si = 0; si < X509_NAME_entry_count(subj2); si++) { // // boilerplate openssl stuff // entry = X509_NAME_get_entry(subj2, si); entryData = X509_NAME_ENTRY_get_data(entry); if (NULL == entryData) { continue; } str = (char*) ASN1_STRING_data(entryData); const char* tempName = "Intel PSE"; if (strncmp(str, tempName, strlen(tempName))==0) {//starting with tempName for (int ii = 0; ii < X509_NAME_entry_count(issuer2); ii++) { entry = X509_NAME_get_entry(issuer2, ii); entryData = X509_NAME_ENTRY_get_data(entry); if (NULL == entryData) { continue; } str = (char*) ASN1_STRING_data(entryData); tempName = "Intel PSE TCB CA"; if (strncmp(str, tempName, strlen(tempName) )==0) {//string start with tempName pseSvnFound = true; // // assume rest of issuer name, after "Intel PSE TCB CA" converts to PSE ISVSVN pseSvn = static_cast(strtol(&str[strlen(tempName)], NULL, 10)); break; } } if (pseSvnFound) { break; } } } if (NULL != cert) { X509_free(cert); } if (pseSvnFound) { break; } } } if (certBio != NULL) BIO_free(certBio); return pseSvn; }