#include #ifdef UA_ENABLE_ENCRYPTION #include #include #include "ua_securitypolicy_mbedtls_common.h" #include #include #include #include #include #include #include #include #include void swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) { UA_ByteString tmp = *bufA; *bufA = *bufB; *bufB = tmp; } void mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key, const UA_ByteString *in, unsigned char *out) { mbedtls_md_hmac_starts(context, key->data, key->length); mbedtls_md_hmac_update(context, in->data, in->length); mbedtls_md_hmac_finish(context, out); } UA_StatusCode mbedtls_generateKey(mbedtls_md_context_t *context, const UA_ByteString *secret, const UA_ByteString *seed, UA_ByteString *out) { size_t hashLen = (size_t)mbedtls_md_get_size(context->md_info); UA_ByteString A_and_seed; UA_ByteString_allocBuffer(&A_and_seed, hashLen + seed->length); memcpy(A_and_seed.data + hashLen, seed->data, seed->length); UA_ByteString ANext_and_seed; UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length); memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length); UA_ByteString A = { hashLen, A_and_seed.data }; UA_ByteString ANext = { hashLen, ANext_and_seed.data }; mbedtls_hmac(context, secret, seed, A.data); UA_StatusCode retval = 0; for(size_t offset = 0; offset < out->length; offset += hashLen) { UA_ByteString outSegment = { hashLen, out->data + offset }; UA_Boolean bufferAllocated = UA_FALSE; // Not enough room in out buffer to write the hash. if(offset + hashLen > out->length) { outSegment.data = NULL; outSegment.length = 0; retval = UA_ByteString_allocBuffer(&outSegment, hashLen); if(retval != UA_STATUSCODE_GOOD) { UA_ByteString_deleteMembers(&A_and_seed); UA_ByteString_deleteMembers(&ANext_and_seed); return retval; } bufferAllocated = UA_TRUE; } mbedtls_hmac(context, secret, &A_and_seed, outSegment.data); mbedtls_hmac(context, secret, &A, ANext.data); if(retval != UA_STATUSCODE_GOOD) { if(bufferAllocated) UA_ByteString_deleteMembers(&outSegment); UA_ByteString_deleteMembers(&A_and_seed); UA_ByteString_deleteMembers(&ANext_and_seed); return retval; } if(bufferAllocated) { memcpy(out->data + offset, outSegment.data, out->length - offset); UA_ByteString_deleteMembers(&outSegment); } swapBuffers(&ANext_and_seed, &A_and_seed); swapBuffers(&ANext, &A); } UA_ByteString_deleteMembers(&A_and_seed); UA_ByteString_deleteMembers(&ANext_and_seed); return UA_STATUSCODE_GOOD; } UA_StatusCode mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message, const UA_ByteString *signature) { /* Compute the sha1 hash */ unsigned char hash[UA_SHA1_LENGTH]; #if MBEDTLS_VERSION_NUMBER >= 0x02070000 mbedtls_sha1_ret(message->data, message->length, hash); #else mbedtls_sha1(message->data, message->length, hash); #endif /* Set the RSA settings */ mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(certificate->pk); if(!rsaContext) return UA_STATUSCODE_BADINTERNALERROR; mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); /* Verify */ int mbedErr = mbedtls_pk_verify(&certificate->pk, MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH, signature->data, signature->length); if(mbedErr) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; return UA_STATUSCODE_GOOD; } UA_StatusCode mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey, mbedtls_ctr_drbg_context *drbgContext, const UA_ByteString *message, UA_ByteString *signature) { unsigned char hash[UA_SHA1_LENGTH]; #if MBEDTLS_VERSION_NUMBER >= 0x02070000 mbedtls_sha1_ret(message->data, message->length, hash); #else mbedtls_sha1(message->data, message->length, hash); #endif mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey); mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, 0); size_t sigLen = 0; int mbedErr = mbedtls_pk_sign(localPrivateKey, MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH, signature->data, &sigLen, mbedtls_ctr_drbg_random, drbgContext); if(mbedErr) return UA_STATUSCODE_BADINTERNALERROR; return UA_STATUSCODE_GOOD; } UA_StatusCode mbedtls_thumbprint_sha1(const UA_ByteString *certificate, UA_ByteString *thumbprint) { if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL)) return UA_STATUSCODE_BADINTERNALERROR; if(thumbprint->length != UA_SHA1_LENGTH) return UA_STATUSCODE_BADINTERNALERROR; /* The certificate thumbprint is always a 20 bit sha1 hash, see Part 4 of the Specification. */ #if MBEDTLS_VERSION_NUMBER >= 0x02070000 mbedtls_sha1_ret(certificate->data, certificate->length, thumbprint->data); #else mbedtls_sha1(certificate->data, certificate->length, thumbprint->data); #endif return UA_STATUSCODE_GOOD; } UA_StatusCode mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context, mbedtls_ctr_drbg_context *drbgContext, UA_ByteString *data, const size_t plainTextBlockSize) { if(data->length % plainTextBlockSize != 0) return UA_STATUSCODE_BADINTERNALERROR; size_t max_blocks = data->length / plainTextBlockSize; UA_ByteString encrypted; UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * context->len); if(retval != UA_STATUSCODE_GOOD) return retval; size_t lenDataToEncrypt = data->length; size_t inOffset = 0; size_t offset = 0; const unsigned char *label = NULL; while(lenDataToEncrypt >= plainTextBlockSize) { int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random, drbgContext, MBEDTLS_RSA_PUBLIC, label, 0, plainTextBlockSize, data->data + inOffset, encrypted.data + offset); if(mbedErr) { UA_ByteString_deleteMembers(&encrypted); return UA_STATUSCODE_BADINTERNALERROR; } inOffset += plainTextBlockSize; offset += context->len; lenDataToEncrypt -= plainTextBlockSize; } memcpy(data->data, encrypted.data, offset); UA_ByteString_deleteMembers(&encrypted); return UA_STATUSCODE_GOOD; } UA_StatusCode mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey, mbedtls_ctr_drbg_context *drbgContext, UA_ByteString *data) { mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey); mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); if(data->length % rsaContext->len != 0) return UA_STATUSCODE_BADINTERNALERROR; size_t inOffset = 0; size_t outOffset = 0; size_t outLength = 0; unsigned char buf[512]; while(inOffset < data->length) { int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random, drbgContext, MBEDTLS_RSA_PRIVATE, NULL, 0, &outLength, data->data + inOffset, buf, 512); if(mbedErr) return UA_STATUSCODE_BADSECURITYCHECKSFAILED; memcpy(data->data + outOffset, buf, outLength); inOffset += rsaContext->len; outOffset += outLength; } data->length = outOffset; return UA_STATUSCODE_GOOD; } #endif