/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2020 (c) Wind River Systems, Inc. * Copyright 2020 (c) basysKom GmbH * Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer) */ #include #include #if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) #include "securitypolicy_common.h" #include #include #define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN 42 #define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH 32 #define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE 16 #define UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH 24 #define UA_SHA1_LENGTH 20 static UA_StatusCode createSigningRequest_sp_basic256(UA_SecurityPolicy *securityPolicy, const UA_String *subjectName, const UA_ByteString *nonce, const UA_KeyValueMap *params, UA_ByteString *csr, UA_ByteString *newPrivateKey) { if(securityPolicy == NULL || csr == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; if(securityPolicy->policyContext == NULL) return UA_STATUSCODE_BADINTERNALERROR; openssl_PolicyContext *pc = (openssl_PolicyContext *) securityPolicy->policyContext; return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey, securityPolicy, subjectName, nonce, csr, newPrivateKey); } /* create the channel context */ static UA_StatusCode Basic256_New_Context(const UA_SecurityPolicy * securityPolicy, const UA_ByteString * remoteCertificate, void ** channelContext) { if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL) return UA_STATUSCODE_BADINTERNALERROR; openssl_ChannelContext * context = (openssl_ChannelContext *) UA_malloc(sizeof(openssl_ChannelContext)); if(context == NULL) return UA_STATUSCODE_BADOUTOFMEMORY; UA_ByteString_init(&context->localSymSigningKey); UA_ByteString_init(&context->localSymEncryptingKey); UA_ByteString_init(&context->localSymIv); UA_ByteString_init(&context->remoteSymSigningKey); UA_ByteString_init(&context->remoteSymEncryptingKey); UA_ByteString_init(&context->remoteSymIv); UA_StatusCode retval = UA_copyCertificate(&context->remoteCertificate, remoteCertificate); if(retval != UA_STATUSCODE_GOOD) { UA_free (context); return retval; } /* decode to X509 */ context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate, EVP_PKEY_RSA); if(context->remoteCertificateX509 == NULL) { UA_ByteString_clear (&context->remoteCertificate); UA_free (context); return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE; } *channelContext = context; return UA_STATUSCODE_GOOD; } static void Basic256_Delete_Context(const UA_SecurityPolicy *policy, void *channelContext) { if(channelContext == NULL) return; openssl_ChannelContext *cc = (openssl_ChannelContext *) channelContext; X509_free(cc->remoteCertificateX509); UA_ByteString_clear(&cc->remoteCertificate); UA_ByteString_clear(&cc->localSymSigningKey); UA_ByteString_clear(&cc->localSymEncryptingKey); UA_ByteString_clear(&cc->localSymIv); UA_ByteString_clear(&cc->remoteSymSigningKey); UA_ByteString_clear(&cc->remoteSymEncryptingKey); UA_ByteString_clear(&cc->remoteSymIv); UA_free(cc); } /* Generates a thumbprint for the specified certificate */ static UA_StatusCode UA_Asy_Basic256_makeCertificateThumbprint(const UA_SecurityPolicy * securityPolicy, const UA_ByteString * certificate, UA_ByteString * thumbprint) { return UA_Openssl_X509_GetCertificateThumbprint (certificate, thumbprint, false); } static size_t UA_AsySig_Basic256_getRemoteSignatureSize(const UA_SecurityPolicy *policy, const void *channelContext) { if(channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_ChannelContext *cc = (const openssl_ChannelContext *) channelContext; UA_Int32 keyLen = 0; UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); return (size_t) keyLen; } static size_t UA_AsySig_Basic256_getLocalSignatureSize(const UA_SecurityPolicy *policy, const void *channelContext) { if (channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_PolicyContext *pc = (const openssl_PolicyContext*)policy->policyContext; UA_Int32 keyLen = 0; UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen); return (size_t) keyLen; } static UA_StatusCode UA_AsySig_Basic256_Verify(const UA_SecurityPolicy *policy, void *channelContext, const UA_ByteString *message, const UA_ByteString *signature) { if(message == NULL || signature == NULL || channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; openssl_ChannelContext * cc = (openssl_ChannelContext *) channelContext; return UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(message, cc->remoteCertificateX509, signature); } static UA_StatusCode UA_AsySig_Basic256_Sign(const UA_SecurityPolicy *policy, void *channelContext, const UA_ByteString *message, UA_ByteString *signature) { if(channelContext == NULL || message == NULL || signature == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_PolicyContext *pc = (const openssl_PolicyContext*)policy->policyContext; return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(message, pc->localPrivateKey, signature); } static size_t UA_AsymEn_Basic256_getRemotePlainTextBlockSize(const UA_SecurityPolicy *policy, const void *channelContext) { if(channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_ChannelContext *cc = (const openssl_ChannelContext *) channelContext; UA_Int32 keyLen = 0; UA_StatusCode retval = UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); if(retval != UA_STATUSCODE_GOOD || keyLen <= (UA_Int32)UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN) return 0; return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN; } static size_t UA_AsymEn_Basic256_getRemoteBlockSize(const UA_SecurityPolicy *policy, const void *channelContext) { if (channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_ChannelContext *cc = (const openssl_ChannelContext *) channelContext; UA_Int32 keyLen = 0; UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); return (size_t) keyLen; } static size_t UA_AsymEn_Basic256_getRemoteKeyLength(const UA_SecurityPolicy *policy, const void *channelContext) { if(channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_ChannelContext *cc = (const openssl_ChannelContext *) channelContext; UA_Int32 keyLen = 0; UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen); return (size_t) keyLen * 8; } static size_t UA_AsymEn_Basic256_getLocalKeyLength(const UA_SecurityPolicy *policy, const void *channelContext) { if (channelContext == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_PolicyContext *pc = (const openssl_PolicyContext*)policy->policyContext; UA_Int32 keyLen = 0; UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen); return (size_t) keyLen * 8; } static UA_StatusCode UA_AsymEn_Basic256_Decrypt(const UA_SecurityPolicy *policy, void *channelContext, UA_ByteString *data) { if(data == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; const openssl_PolicyContext *pc = (const openssl_PolicyContext*)policy->policyContext; return UA_Openssl_RSA_Oaep_Decrypt(data, pc->localPrivateKey); } static UA_StatusCode UA_AsymEn_Basic256_Encrypt(const UA_SecurityPolicy *policy, void *channelContext, UA_ByteString *data) { if(channelContext == NULL || data == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; openssl_ChannelContext * cc = (openssl_ChannelContext *) channelContext; return UA_Openssl_RSA_OAEP_Encrypt(data, UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN, cc->remoteCertificateX509); } static UA_StatusCode UA_Sym_Basic256_generateNonce(const UA_SecurityPolicy *policy, void *channelContext, UA_ByteString *out) { UA_Int32 rc = RAND_bytes(out->data, (int) out->length); if(rc != 1) return UA_STATUSCODE_BADUNEXPECTEDERROR; return UA_STATUSCODE_GOOD; } static UA_StatusCode UA_Sym_Basic256_generateKey(const UA_SecurityPolicy *policy, void *channelContext, const UA_ByteString *secret, const UA_ByteString *seed, UA_ByteString *out) { return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out); } static size_t UA_SymEn_Basic256_getLocalKeyLength(const UA_SecurityPolicy *policy, const void *channelContext) { /* 32 bytes 256 bits */ return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH; } static size_t UA_SymEn_Basic256_getBlockSize(const UA_SecurityPolicy *policy, const void *channelContext) { return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE; } static size_t UA_SymEn_Basic256_getRemoteKeyLength(const UA_SecurityPolicy *policy, const void *channelContext) { /* 32 bytes 256 bits */ return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH; } static UA_StatusCode UA_SymEn_Basic256_Encrypt(const UA_SecurityPolicy *policy, void *channelContext, UA_ByteString *data) { if(channelContext == NULL || data == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; openssl_ChannelContext * cc = (openssl_ChannelContext *) channelContext; return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey, data); } static UA_StatusCode UA_SymEn_Basic256_Decrypt(const UA_SecurityPolicy *policy, void *channelContext, UA_ByteString *data) { if(channelContext == NULL || data == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; openssl_ChannelContext * cc = (openssl_ChannelContext *) channelContext; return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data); } static size_t UA_SymSig_Basic256_getKeyLength(const UA_SecurityPolicy *policy, const void *channelContext) { return UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH; } static size_t UA_SymSig_Basic256_getSignatureSize (const UA_SecurityPolicy *policy, const void *channelContext) { return UA_SHA1_LENGTH; } static UA_StatusCode UA_SymSig_Basic256_Verify(const UA_SecurityPolicy *policy, void *channelContext, const UA_ByteString *message, const UA_ByteString *signature) { if(channelContext == NULL || message == NULL || signature == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; openssl_ChannelContext * cc = (openssl_ChannelContext *) channelContext; return UA_OpenSSL_HMAC_SHA1_Verify (message, &cc->remoteSymSigningKey, signature); } static UA_StatusCode UA_SymSig_Basic256_Sign(const UA_SecurityPolicy *policy, void *channelContext, const UA_ByteString *message, UA_ByteString *signature) { if(channelContext == NULL || message == NULL || signature == NULL) return UA_STATUSCODE_BADINVALIDARGUMENT; openssl_ChannelContext * cc = (openssl_ChannelContext *) channelContext; return UA_OpenSSL_HMAC_SHA1_Sign(message, &cc->localSymSigningKey, signature); } UA_StatusCode UA_SecurityPolicy_Basic256(UA_SecurityPolicy *sp, const UA_ByteString localCertificate, const UA_ByteString localPrivateKey, const UA_Logger *logger) { UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY, "!! WARNING !! The Basic256 SecurityPolicy is unsecure. " "There are known attacks that break the encryption."); memset(sp, 0, sizeof(UA_SecurityPolicy)); sp->logger = logger; sp->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256\0"); sp->certificateGroupId = UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP); sp->certificateTypeId = UA_NS0ID(RSAMINAPPLICATIONCERTIFICATETYPE); sp->securityLevel = 0; sp->policyType = UA_SECURITYPOLICYTYPE_RSA; /* Asymmetric Signature */ UA_SecurityPolicySignatureAlgorithm *asymSig = &sp->asymSignatureAlgorithm; asymSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0"); asymSig->verify = UA_AsySig_Basic256_Verify; asymSig->sign = UA_AsySig_Basic256_Sign; asymSig->getLocalSignatureSize = UA_AsySig_Basic256_getLocalSignatureSize; asymSig->getRemoteSignatureSize = UA_AsySig_Basic256_getRemoteSignatureSize; /* Asymmetric Encryption */ UA_SecurityPolicyEncryptionAlgorithm *asymEnc = &sp->asymEncryptionAlgorithm; asymEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0"); asymEnc->encrypt = UA_AsymEn_Basic256_Encrypt; asymEnc->decrypt = UA_AsymEn_Basic256_Decrypt; asymEnc->getLocalKeyLength = UA_AsymEn_Basic256_getLocalKeyLength; asymEnc->getRemoteKeyLength = UA_AsymEn_Basic256_getRemoteKeyLength; asymEnc->getRemoteBlockSize = UA_AsymEn_Basic256_getRemoteBlockSize; asymEnc->getRemotePlainTextBlockSize = UA_AsymEn_Basic256_getRemotePlainTextBlockSize; /* Symmetric Signature */ UA_SecurityPolicySignatureAlgorithm *symSig = &sp->symSignatureAlgorithm; symSig->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0"); symSig->verify = UA_SymSig_Basic256_Verify; symSig->sign = UA_SymSig_Basic256_Sign; symSig->getLocalSignatureSize = UA_SymSig_Basic256_getSignatureSize; symSig->getRemoteSignatureSize = UA_SymSig_Basic256_getSignatureSize; symSig->getLocalKeyLength = UA_SymSig_Basic256_getKeyLength; symSig->getRemoteKeyLength = UA_SymSig_Basic256_getKeyLength; /* Symmetric Encryption */ UA_SecurityPolicyEncryptionAlgorithm *symEnc = &sp->symEncryptionAlgorithm; symEnc->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0"); symEnc->encrypt = UA_SymEn_Basic256_Encrypt; symEnc->decrypt = UA_SymEn_Basic256_Decrypt; symEnc->getLocalKeyLength = UA_SymEn_Basic256_getLocalKeyLength; symEnc->getRemoteKeyLength = UA_SymEn_Basic256_getRemoteKeyLength; symEnc->getRemoteBlockSize = UA_SymEn_Basic256_getBlockSize; symEnc->getRemotePlainTextBlockSize = UA_SymEn_Basic256_getBlockSize; /* Use the same signature algorithm as the asymmetric component for * certificate signing (see standard) */ sp->certSignatureAlgorithm = sp->asymSignatureAlgorithm; /* Direct Method Pointers */ sp->newChannelContext = Basic256_New_Context; sp->deleteChannelContext = Basic256_Delete_Context; sp->setLocalSymEncryptingKey = UA_OpenSSL_setLocalSymEncryptingKey_generic; sp->setLocalSymSigningKey = UA_OpenSSL_setLocalSymSigningKey_generic; sp->setLocalSymIv = UA_OpenSSL_setLocalSymIv_generic; sp->setRemoteSymEncryptingKey = UA_OpenSSL_setRemoteSymEncryptingKey_generic; sp->setRemoteSymSigningKey = UA_OpenSSL_setRemoteSymSigningKey_generic; sp->setRemoteSymIv = UA_OpenSSL_setRemoteSymIv_generic; sp->compareCertificate = UA_OpenSSL_compareCertificate_generic; sp->generateKey = UA_Sym_Basic256_generateKey; sp->generateNonce = UA_Sym_Basic256_generateNonce; sp->nonceLength = 32; sp->makeCertThumbprint = UA_Asy_Basic256_makeCertificateThumbprint; sp->compareCertThumbprint = UA_OpenSSL_SecurityPolicy_compareCertThumbprint_generic; sp->updateCertificate = UA_OpenSSL_SecurityPolicy_updateCertificate_generic; sp->createSigningRequest = createSigningRequest_sp_basic256; sp->clear = UA_OpenSSL_Policy_clearContext_generic; /* Parse the certificate */ UA_Openssl_Init(); UA_StatusCode res = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &sp->localCertificate, EVP_PKEY_RSA); if(res != UA_STATUSCODE_GOOD) return res; /* Create the policy context */ res = UA_OpenSSL_Policy_newContext_generic(sp, localPrivateKey, EVP_PKEY_RSA, logger); if(res != UA_STATUSCODE_GOOD) { UA_ByteString_clear(&sp->localCertificate); return res; } return UA_STATUSCODE_GOOD; } #endif