mirror of
https://github.com/open62541/open62541.git
synced 2026-10-26 02:20:27 +08:00
418 lines
18 KiB
C
418 lines
18 KiB
C
/* 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 <open62541/plugin/securitypolicy_default.h>
|
|
#include <open62541/util.h>
|
|
|
|
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
|
|
|
|
#include "securitypolicy_common.h"
|
|
|
|
#include <openssl/x509.h>
|
|
#include <openssl/rand.h>
|
|
|
|
#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
|