mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
feat(plugin): add OpenSSL plugin for ECC P-256
Add http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256 policy support in OpenSSL plugin.
This commit is contained in:
parent
f18fa900f8
commit
308d8e2759
@ -997,6 +997,7 @@ if(UA_ENABLE_ENCRYPTION_OPENSSL OR UA_ENABLE_ENCRYPTION_LIBRESSL OR UA_ENABLE_AM
|
||||
${PROJECT_SOURCE_DIR}/plugins/crypto/openssl/securitypolicy_basic256sha256.c
|
||||
${PROJECT_SOURCE_DIR}/plugins/crypto/openssl/securitypolicy_aes128sha256rsaoaep.c
|
||||
${PROJECT_SOURCE_DIR}/plugins/crypto/openssl/securitypolicy_aes256sha256rsapss.c
|
||||
${PROJECT_SOURCE_DIR}/plugins/crypto/openssl/securitypolicy_eccnistp256.c
|
||||
${PROJECT_SOURCE_DIR}/plugins/crypto/openssl/create_certificate.c
|
||||
${PROJECT_SOURCE_DIR}/plugins/crypto/openssl/certificategroup.c)
|
||||
endif()
|
||||
|
@ -873,6 +873,12 @@ UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
|
||||
*keySize = EVP_PKEY_get_size(pkey) * 8;
|
||||
#else
|
||||
*keySize = RSA_size(get_pkey_rsa(pkey)) * 8;
|
||||
#endif
|
||||
} else if(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) {
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
*keySize = EVP_PKEY_get_size(pkey) * 8;
|
||||
#else
|
||||
*keySize = ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)) * 8;
|
||||
#endif
|
||||
} else {
|
||||
EVP_PKEY_free(pkey);
|
||||
|
@ -30,12 +30,22 @@ modification history
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/kdf.h>
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#include "securitypolicy_common.h"
|
||||
|
||||
#define SHA1_DIGEST_LENGTH 20 /* 160 bits */
|
||||
#define RSA_DECRYPT_BUFFER_LENGTH 2048 /* bytes */
|
||||
|
||||
/* Strings for ECC policies */
|
||||
UA_String serverLabel = UA_STRING_STATIC("opcua-server");
|
||||
UA_String clientLabel = UA_STRING_STATIC("opcua-client");
|
||||
|
||||
/* Cast to prevent warnings in LibreSSL */
|
||||
#define SHA256EVP() ((EVP_MD *)(uintptr_t)EVP_sha256())
|
||||
|
||||
@ -1421,3 +1431,652 @@ UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
static UA_StatusCode
|
||||
UA_OpenSSL_ECDH (const int nid,
|
||||
EVP_PKEY * keyPairLocal,
|
||||
const UA_ByteString * keyPublicRemote,
|
||||
UA_ByteString * sharedSecretOut) {
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
EVP_PKEY_CTX * pctx = NULL;
|
||||
EVP_PKEY_CTX * kctx = NULL;
|
||||
EVP_PKEY * remotePubKey = NULL;
|
||||
EVP_PKEY * params = NULL;
|
||||
UA_ByteString * keyPublicRemoteEncoded = NULL;
|
||||
|
||||
keyPublicRemoteEncoded = UA_ByteString_new();
|
||||
if(keyPublicRemoteEncoded == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(keyPublicRemoteEncoded, keyPublicRemote->length+1)) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
keyPublicRemoteEncoded->data[0] = 0x04;
|
||||
memcpy(&keyPublicRemoteEncoded->data[1], keyPublicRemote->data, keyPublicRemote->length);
|
||||
|
||||
remotePubKey = EVP_PKEY_new();
|
||||
if(remotePubKey == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||||
if (pctx == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_paramgen_init(pctx) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_paramgen(pctx, ¶ms) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_copy_parameters(remotePubKey, params) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
if(EVP_PKEY_set1_encoded_public_key(remotePubKey, keyPublicRemoteEncoded->data, keyPublicRemoteEncoded->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
#else
|
||||
if(EVP_PKEY_set1_tls_encodedpoint(remotePubKey, keyPublicRemoteEncoded->data, keyPublicRemoteEncoded->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
#endif
|
||||
|
||||
kctx = EVP_PKEY_CTX_new(keyPairLocal, NULL);
|
||||
if(kctx == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_derive_init(kctx) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_derive_set_peer(kctx, remotePubKey) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_derive(kctx, NULL, &sharedSecretOut->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(sharedSecretOut, sharedSecretOut->length)) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_derive(kctx, sharedSecretOut->data, &sharedSecretOut->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
errout:
|
||||
UA_ByteString_clear(keyPublicRemoteEncoded);
|
||||
UA_ByteString_delete(keyPublicRemoteEncoded);
|
||||
EVP_PKEY_free(remotePubKey);
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_CTX_free(kctx);
|
||||
EVP_PKEY_free(params);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_OpenSSL_ECC_GenerateSalt (const size_t L,
|
||||
const UA_ByteString * label,
|
||||
const UA_ByteString * key1,
|
||||
const UA_ByteString * key2,
|
||||
UA_ByteString * salt) {
|
||||
size_t saltLen = sizeof(uint16_t) + label->length + key1->length + key2->length;
|
||||
|
||||
if (salt == NULL || UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(salt, saltLen)) {
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
|
||||
salt->data[0] = (L) & 0xFF;
|
||||
salt->data[1] = (L >> 8) & 0xFF;
|
||||
|
||||
UA_Byte * saltPtr = &salt->data[2];
|
||||
|
||||
memcpy(saltPtr, label->data, label->length);
|
||||
saltPtr += label->length;
|
||||
memcpy(saltPtr, key1->data, key1->length);
|
||||
saltPtr += key1->length;
|
||||
memcpy(saltPtr, key2->data, key2->length);
|
||||
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
static UA_StatusCode
|
||||
UA_OpenSSL_HKDF (char * hashAlgorithm,
|
||||
const UA_ByteString * ikm,
|
||||
const UA_ByteString * salt,
|
||||
const UA_ByteString * info,
|
||||
UA_ByteString * out) {
|
||||
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
EVP_KDF * kdf = NULL;
|
||||
EVP_KDF_CTX * kctx = NULL;
|
||||
OSSL_PARAM params[5];
|
||||
OSSL_PARAM * p = params;
|
||||
|
||||
kdf = EVP_KDF_fetch(NULL, "HKDF", NULL);
|
||||
if(kdf == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
kctx = EVP_KDF_CTX_new(kdf);
|
||||
if(kctx == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, hashAlgorithm, strlen(hashAlgorithm));
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, ikm->data, ikm->length);
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info->data, info->length);
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, salt->data, salt->length);
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
if(EVP_KDF_derive(kctx, out->data, out->length, params) <= 0) {
|
||||
ERR_print_errors_fp(stdout);
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
errout:
|
||||
EVP_KDF_free(kdf);
|
||||
EVP_KDF_CTX_free(kctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
|
||||
static UA_StatusCode
|
||||
UA_OpenSSL_HKDF (char * hashAlgorithm,
|
||||
const UA_ByteString * ikm,
|
||||
const UA_ByteString * salt,
|
||||
const UA_ByteString * info,
|
||||
UA_ByteString * out) {
|
||||
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
const EVP_MD *md = NULL;
|
||||
|
||||
/* Retrieve the digest pointer */
|
||||
md = EVP_get_digestbyname(hashAlgorithm);
|
||||
if (md == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
||||
if (EVP_PKEY_derive_init(pctx) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
if (EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt->data, salt->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, ikm->data, ikm->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info->data, info->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
if (EVP_PKEY_derive(pctx, out->data, &out->length) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
errout:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
UA_StatusCode
|
||||
UA_OpenSSL_ECC_DeriveKeys (const int curveID,
|
||||
char * hashAlgorithm,
|
||||
const UA_ApplicationType applicationType,
|
||||
EVP_PKEY * localEphemeralKeyPair,
|
||||
const UA_ByteString * key1,
|
||||
const UA_ByteString * key2,
|
||||
UA_ByteString * out) {
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
UA_Boolean generateLocal = true;
|
||||
const UA_ByteString * remotePublicKey = NULL;
|
||||
UA_ByteString * sharedSecret = NULL;
|
||||
UA_ByteString * salt = NULL;
|
||||
|
||||
/* The order of ephemeral public keys (key1 and key2) tells us whether we
|
||||
* need to generate the local keys or the remote keys. To figure that out,
|
||||
* we compare the public part of localEphemeralKeyPair with key1 and key2. */
|
||||
UA_Byte * keyPubEnc = NULL;
|
||||
size_t keyPubEncSize = 0;
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
keyPubEncSize = EVP_PKEY_get1_encoded_public_key(localEphemeralKeyPair, &keyPubEnc);
|
||||
#else
|
||||
keyPubEncSize = EVP_PKEY_get1_tls_encodedpoint(localEphemeralKeyPair, &keyPubEnc);
|
||||
#endif
|
||||
if (keyPubEncSize <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Comparing from the second byte since the first byte has 0x04 from the encoding */
|
||||
if (memcmp(&keyPubEnc[1], key1->data, key1->length) == 0) {
|
||||
/* Remote keys */
|
||||
generateLocal = false;
|
||||
remotePublicKey = key2;
|
||||
}
|
||||
else if (memcmp(&keyPubEnc[1], key2->data, key2->length) == 0) {
|
||||
/* Local keys */
|
||||
generateLocal = true;
|
||||
remotePublicKey = key1;
|
||||
}
|
||||
else {
|
||||
/* invalid */
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Use ECDH to calculate shared secret */
|
||||
sharedSecret = UA_ByteString_new();
|
||||
if (sharedSecret == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
if (UA_STATUSCODE_GOOD != UA_OpenSSL_ECDH(curveID, localEphemeralKeyPair, remotePublicKey, sharedSecret)) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Select label for salt generation */
|
||||
UA_ByteString *label = NULL;
|
||||
|
||||
switch(applicationType) {
|
||||
case UA_APPLICATIONTYPE_SERVER:
|
||||
if (generateLocal)
|
||||
label = &serverLabel;
|
||||
else
|
||||
label = &clientLabel;
|
||||
break;
|
||||
case UA_APPLICATIONTYPE_CLIENT:
|
||||
if (generateLocal)
|
||||
label = &clientLabel;
|
||||
else
|
||||
label = &serverLabel;
|
||||
break;
|
||||
default:
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculate salt */
|
||||
salt = UA_ByteString_new();
|
||||
if (salt == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
if (UA_STATUSCODE_GOOD != UA_OpenSSL_ECC_GenerateSalt(out->length, label, key1, key2, salt)) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Call HKDF to derive keys */
|
||||
if (UA_STATUSCODE_GOOD != UA_OpenSSL_HKDF(hashAlgorithm, sharedSecret, salt, salt, out)) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
errout:
|
||||
OPENSSL_free(keyPubEnc);
|
||||
UA_ByteString_clear(sharedSecret);
|
||||
UA_ByteString_delete(sharedSecret);
|
||||
UA_ByteString_clear(salt);
|
||||
UA_ByteString_delete(salt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_OpenSSL_ECC_GenerateKey(const int curveId,
|
||||
EVP_PKEY ** keyPairOut,
|
||||
UA_ByteString * keyPublicEncOut) {
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
EVP_PKEY_CTX * pctx = NULL;
|
||||
EVP_PKEY_CTX * kctx = NULL;
|
||||
EVP_PKEY * params = NULL;
|
||||
size_t keyPubEncSize = 0;
|
||||
UA_Byte * keyPubEnc = NULL;
|
||||
|
||||
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||||
if (pctx == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(EVP_PKEY_paramgen_init(pctx) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curveId) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_paramgen(pctx, ¶ms) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
kctx = EVP_PKEY_CTX_new(params, NULL);
|
||||
if (kctx == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_keygen_init(kctx) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_keygen(kctx, keyPairOut) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
keyPubEncSize = EVP_PKEY_get1_encoded_public_key(*keyPairOut, &keyPubEnc);
|
||||
#else
|
||||
keyPubEncSize = EVP_PKEY_get1_tls_encodedpoint(*keyPairOut, &keyPubEnc);
|
||||
#endif
|
||||
if (keyPubEncSize <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(keyPublicEncOut->data, &keyPubEnc[1], keyPubEncSize-1);
|
||||
|
||||
errout:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(params);
|
||||
EVP_PKEY_CTX_free(kctx);
|
||||
OPENSSL_free(keyPubEnc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_Openssl_ECDSA_Sign(const UA_ByteString * message,
|
||||
EVP_PKEY * privateKey,
|
||||
const EVP_MD * evpMd,
|
||||
UA_ByteString * outSignature) {
|
||||
EVP_MD_CTX * mdctx = NULL;
|
||||
int opensslRet = 0;
|
||||
EVP_PKEY_CTX * evpKeyCtx = NULL;
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
UA_ByteString * signatureEnc = NULL;
|
||||
ECDSA_SIG* signatureRaw = NULL;
|
||||
const BIGNUM * pr = NULL;
|
||||
const BIGNUM * ps = NULL;
|
||||
size_t sizeEncCoordinate = 0;
|
||||
|
||||
if (privateKey == NULL) {
|
||||
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||
}
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
if (mdctx == NULL) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
opensslRet = EVP_DigestSignInit (mdctx, &evpKeyCtx, evpMd, NULL, privateKey);
|
||||
if (opensslRet != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
opensslRet = EVP_DigestSignUpdate (mdctx, message->data, message->length);
|
||||
if (opensslRet != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Temporary buffer for OpenSSL-internal signature computation */
|
||||
signatureEnc = UA_ByteString_new();
|
||||
if (signatureEnc == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Length required for internal computing */
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
|
||||
signatureEnc->length = EVP_PKEY_get_size(privateKey);
|
||||
#else
|
||||
signatureEnc->length = ECDSA_size(EVP_PKEY_get0_EC_KEY(privateKey));
|
||||
#endif
|
||||
|
||||
if (UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(signatureEnc, signatureEnc->length)) {
|
||||
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
opensslRet = EVP_DigestSignFinal(mdctx, signatureEnc->data, &signatureEnc->length);
|
||||
if (opensslRet != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// using temp pointer since the function call increments it
|
||||
const UA_Byte * ptmpData = signatureEnc->data;
|
||||
|
||||
signatureRaw = d2i_ECDSA_SIG(NULL, &ptmpData, signatureEnc->length);
|
||||
if (signatureRaw == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ECDSA_SIG_get0(signatureRaw, &pr, &ps);
|
||||
if (pr == NULL || ps == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
sizeEncCoordinate = outSignature->length / 2;
|
||||
if(sizeEncCoordinate <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (BN_bn2binpad(pr, outSignature->data, sizeEncCoordinate) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (BN_bn2binpad(ps, outSignature->data + sizeEncCoordinate, sizeEncCoordinate) <= 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
errout:
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
UA_ByteString_clear(signatureEnc);
|
||||
UA_ByteString_delete(signatureEnc);
|
||||
ECDSA_SIG_free(signatureRaw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_Openssl_ECDSA_Verify(const UA_ByteString * message,
|
||||
const EVP_MD * evpMd,
|
||||
X509 * publicKeyX509,
|
||||
const UA_ByteString * signature) {
|
||||
UA_StatusCode ret = UA_STATUSCODE_GOOD;
|
||||
EVP_MD_CTX *mdctx = NULL;
|
||||
BIGNUM *pr = NULL;
|
||||
BIGNUM *ps = NULL;
|
||||
UA_ByteString *signatureEnc = NULL;
|
||||
ECDSA_SIG *signatureRaw = NULL;
|
||||
EVP_PKEY *evpPublicKey = NULL;
|
||||
size_t sizeEncCoordinate = 0;
|
||||
|
||||
if (evpMd == EVP_sha256()) {
|
||||
sizeEncCoordinate = 32;
|
||||
} else if (evpMd == EVP_sha384()) {
|
||||
sizeEncCoordinate = 48;
|
||||
} else {
|
||||
ret = UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
pr = BN_bin2bn(signature->data, sizeEncCoordinate, NULL);
|
||||
ps = BN_bin2bn(signature->data + sizeEncCoordinate, sizeEncCoordinate, NULL);
|
||||
if(pr == NULL || ps == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
signatureRaw = ECDSA_SIG_new();
|
||||
if (signatureRaw == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if(ECDSA_SIG_set0(signatureRaw, pr, ps) != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
signatureEnc = UA_ByteString_new();
|
||||
if (signatureEnc == NULL) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// this call is to find out the length of the encoded signature
|
||||
signatureEnc->length = i2d_ECDSA_SIG(signatureRaw, NULL);
|
||||
if (signatureEnc->length == 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (UA_STATUSCODE_GOOD != UA_ByteString_allocBuffer(signatureEnc, signatureEnc->length)) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// use temp pointer since the function call increments it
|
||||
UA_Byte * ptmpData = signatureEnc->data;
|
||||
|
||||
signatureEnc->length = i2d_ECDSA_SIG(signatureRaw, &ptmpData);
|
||||
if (signatureEnc->length == 0) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
if(!mdctx) {
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
|
||||
evpPublicKey = X509_get_pubkey(publicKeyX509);
|
||||
if(!evpPublicKey) {
|
||||
ret = UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX * evpKeyCtx = NULL;
|
||||
int opensslRet = EVP_DigestVerifyInit(mdctx, &evpKeyCtx, evpMd,
|
||||
NULL, evpPublicKey);
|
||||
if(opensslRet != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
opensslRet = EVP_DigestVerifyUpdate (mdctx, message->data, message->length);
|
||||
if(opensslRet != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
opensslRet = EVP_DigestVerifyFinal(mdctx, signatureEnc->data, signatureEnc->length);
|
||||
if(opensslRet != 1) {
|
||||
ret = UA_STATUSCODE_BADINTERNALERROR;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = UA_STATUSCODE_GOOD;
|
||||
|
||||
errout:
|
||||
EVP_PKEY_free(evpPublicKey);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
ECDSA_SIG_free(signatureRaw);
|
||||
UA_ByteString_clear(signatureEnc);
|
||||
UA_ByteString_delete(signatureEnc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UA_StatusCode
|
||||
UA_OpenSSL_ECC_NISTP256_GenerateKey (EVP_PKEY ** keyPairOut,
|
||||
UA_ByteString * keyPublicEncOut) {
|
||||
return UA_OpenSSL_ECC_GenerateKey (EC_curve_nist2nid("P-256"), keyPairOut,
|
||||
keyPublicEncOut);
|
||||
}
|
||||
|
||||
UA_StatusCode
|
||||
UA_Openssl_ECDSA_SHA256_Sign (const UA_ByteString * message,
|
||||
EVP_PKEY * privateKey,
|
||||
UA_ByteString * outSignature) {
|
||||
return UA_Openssl_ECDSA_Sign (message, privateKey, EVP_sha256(),
|
||||
outSignature);
|
||||
}
|
||||
|
||||
UA_StatusCode
|
||||
UA_Openssl_ECDSA_SHA256_Verify (const UA_ByteString * message,
|
||||
X509 * publicKeyX509,
|
||||
const UA_ByteString * signature) {
|
||||
return UA_Openssl_ECDSA_Verify (message, EVP_sha256(), publicKeyX509,
|
||||
signature);
|
||||
}
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright 2020 (c) Wind River Systems, Inc.
|
||||
* Copyright 2020 (c) basysKom GmbH
|
||||
* Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
|
||||
*
|
||||
*/
|
||||
|
||||
@ -106,6 +107,29 @@ UA_Openssl_RSA_PSS_SHA256_Sign (const UA_ByteString * message,
|
||||
EVP_PKEY * privateKey,
|
||||
UA_ByteString * outSignature);
|
||||
|
||||
UA_StatusCode
|
||||
UA_OpenSSL_ECC_NISTP256_GenerateKey (EVP_PKEY ** keyPairOut,
|
||||
UA_ByteString * keyPublicEncOut);
|
||||
|
||||
UA_StatusCode
|
||||
UA_OpenSSL_ECC_DeriveKeys (const int curveID,
|
||||
char * hashAlgorithm,
|
||||
const UA_ApplicationType applicationType,
|
||||
EVP_PKEY * localEphemeralKeyPair,
|
||||
const UA_ByteString * key1,
|
||||
const UA_ByteString * key2,
|
||||
UA_ByteString * out);
|
||||
|
||||
UA_StatusCode
|
||||
UA_Openssl_ECDSA_SHA256_Sign (const UA_ByteString * message,
|
||||
EVP_PKEY * privateKey,
|
||||
UA_ByteString * outSignature);
|
||||
|
||||
UA_StatusCode
|
||||
UA_Openssl_ECDSA_SHA256_Verify (const UA_ByteString * message,
|
||||
X509 * publicKeyX509,
|
||||
const UA_ByteString * signature);
|
||||
|
||||
UA_StatusCode
|
||||
UA_OpenSSL_HMAC_SHA256_Verify(const UA_ByteString *message,
|
||||
const UA_ByteString *key,
|
||||
|
722
plugins/crypto/openssl/securitypolicy_eccnistp256.c
Normal file
722
plugins/crypto/openssl/securitypolicy_eccnistp256.c
Normal file
@ -0,0 +1,722 @@
|
||||
/* 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 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
|
||||
*/
|
||||
|
||||
#include <open62541/plugin/securitypolicy_default.h>
|
||||
#include <open62541/util.h>
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
|
||||
#include "securitypolicy_common.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#define UA_SHA256_LENGTH 32 /* 256 bit */
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNING_KEY_LENGTH 32
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH 64
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH 32
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH 16
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE 16
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
|
||||
#define UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES 64
|
||||
|
||||
typedef struct {
|
||||
EVP_PKEY *localPrivateKey;
|
||||
EVP_PKEY *csrLocalPrivateKey;
|
||||
UA_ByteString localCertThumbprint;
|
||||
const UA_Logger *logger;
|
||||
UA_ApplicationType applicationType;
|
||||
struct _Channel_Context_EccNistP256 *channelContext;
|
||||
} Policy_Context_EccNistP256;
|
||||
|
||||
typedef struct _Channel_Context_EccNistP256 {
|
||||
EVP_PKEY * localEphemeralKeyPair;
|
||||
UA_ByteString localSymSigningKey;
|
||||
UA_ByteString localSymEncryptingKey;
|
||||
UA_ByteString localSymIv;
|
||||
UA_ByteString remoteSymSigningKey;
|
||||
UA_ByteString remoteSymEncryptingKey;
|
||||
UA_ByteString remoteSymIv;
|
||||
|
||||
Policy_Context_EccNistP256 *policyContext;
|
||||
UA_ByteString remoteCertificate;
|
||||
X509 *remoteCertificateX509; /* X509 */
|
||||
} Channel_Context_EccNistP256;
|
||||
|
||||
/* create the policy context */
|
||||
|
||||
static UA_StatusCode
|
||||
UA_Policy_EccNistP256_New_Context(UA_SecurityPolicy *securityPolicy,
|
||||
const UA_ByteString localPrivateKey,
|
||||
const UA_ApplicationType applicationType,
|
||||
const UA_Logger *logger) {
|
||||
Policy_Context_EccNistP256 *context =
|
||||
(Policy_Context_EccNistP256 *)UA_malloc(
|
||||
sizeof(Policy_Context_EccNistP256));
|
||||
if(context == NULL) {
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
|
||||
context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
|
||||
if (!context->localPrivateKey) {
|
||||
UA_free(context);
|
||||
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||
}
|
||||
|
||||
context->csrLocalPrivateKey = NULL;
|
||||
|
||||
UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
|
||||
&securityPolicy->localCertificate, &context->localCertThumbprint, true);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
EVP_PKEY_free(context->localPrivateKey);
|
||||
UA_free(context);
|
||||
return retval;
|
||||
}
|
||||
|
||||
context->applicationType = applicationType;
|
||||
context->logger = logger;
|
||||
securityPolicy->policyContext = context;
|
||||
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
/* clear the policy context */
|
||||
|
||||
static void
|
||||
UA_Policy_EccNistP256_Clear_Context(UA_SecurityPolicy *policy) {
|
||||
if(policy == NULL)
|
||||
return;
|
||||
|
||||
UA_ByteString_clear(&policy->localCertificate);
|
||||
|
||||
/* delete all allocated members in the context */
|
||||
|
||||
Policy_Context_EccNistP256 *pc =
|
||||
(Policy_Context_EccNistP256 *)policy->policyContext;
|
||||
if (pc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
EVP_PKEY_free(pc->localPrivateKey);
|
||||
pc->localPrivateKey = NULL;
|
||||
EVP_PKEY_free(pc->csrLocalPrivateKey);
|
||||
pc->csrLocalPrivateKey = NULL;
|
||||
UA_ByteString_clear(&pc->localCertThumbprint);
|
||||
UA_free(pc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
createSigningRequest_sp_eccnistp256(UA_SecurityPolicy *securityPolicy,
|
||||
const UA_String *subjectName,
|
||||
const UA_ByteString *nonce,
|
||||
const UA_KeyValueMap *params,
|
||||
UA_ByteString *csr,
|
||||
UA_ByteString *newPrivateKey) {
|
||||
/* Check parameter */
|
||||
if(!securityPolicy || !csr)
|
||||
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||
|
||||
if(!securityPolicy->policyContext)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
Policy_Context_EccNistP256 *pc =
|
||||
(Policy_Context_EccNistP256*)securityPolicy->policyContext;
|
||||
|
||||
return UA_OpenSSL_CreateSigningRequest(pc->localPrivateKey, &pc->csrLocalPrivateKey,
|
||||
securityPolicy, subjectName,
|
||||
nonce, csr, newPrivateKey);
|
||||
}
|
||||
|
||||
|
||||
static UA_StatusCode
|
||||
updateCertificateAndPrivateKey_sp_EccNistP256(UA_SecurityPolicy *securityPolicy,
|
||||
const UA_ByteString newCertificate,
|
||||
const UA_ByteString newPrivateKey) {
|
||||
if(securityPolicy == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
if(securityPolicy->policyContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
Policy_Context_EccNistP256 *pc =
|
||||
(Policy_Context_EccNistP256 *)securityPolicy->policyContext;
|
||||
|
||||
UA_ByteString_clear(&securityPolicy->localCertificate);
|
||||
|
||||
UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
|
||||
&newCertificate, &securityPolicy->localCertificate);
|
||||
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
|
||||
/* Set the new private key */
|
||||
EVP_PKEY_free(pc->localPrivateKey);
|
||||
|
||||
pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);
|
||||
|
||||
if(!pc->localPrivateKey) {
|
||||
retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
UA_ByteString_clear(&pc->localCertThumbprint);
|
||||
|
||||
retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
|
||||
&pc->localCertThumbprint, true);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
error:
|
||||
UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
|
||||
"Could not update certificate and private key");
|
||||
if(securityPolicy->policyContext != NULL)
|
||||
UA_Policy_EccNistP256_Clear_Context(securityPolicy);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* create the channel context */
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelModule_EccNistP256_New_Context(const UA_SecurityPolicy *securityPolicy,
|
||||
const UA_ByteString *remoteCertificate,
|
||||
void **channelContext) {
|
||||
if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL) {
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
}
|
||||
Channel_Context_EccNistP256 *context =
|
||||
(Channel_Context_EccNistP256 *)UA_malloc(
|
||||
sizeof(Channel_Context_EccNistP256));
|
||||
if(context == NULL) {
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
|
||||
context->localEphemeralKeyPair = NULL;
|
||||
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);
|
||||
if (context->remoteCertificateX509 == NULL) {
|
||||
UA_ByteString_clear (&context->remoteCertificate);
|
||||
UA_free (context);
|
||||
return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
|
||||
}
|
||||
|
||||
context->policyContext =
|
||||
(Policy_Context_EccNistP256 *)(securityPolicy->policyContext);
|
||||
|
||||
/* This reference is needed in UA_Sym_EccNistP256_generateNonce to get
|
||||
* access to the localEphemeralKeyPair variable in the channelContext */
|
||||
context->policyContext->channelContext = context;
|
||||
|
||||
*channelContext = context;
|
||||
|
||||
UA_LOG_INFO(
|
||||
securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
|
||||
"The EccNistP256 security policy channel with openssl is created.");
|
||||
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
/* delete the channel context */
|
||||
|
||||
static void
|
||||
UA_ChannelModule_EccNistP256_Delete_Context(void *channelContext) {
|
||||
if(channelContext != NULL) {
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)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);
|
||||
EVP_PKEY_free(cc->localEphemeralKeyPair);
|
||||
|
||||
/* Remove reference */
|
||||
cc->policyContext->channelContext = NULL;
|
||||
|
||||
UA_LOG_INFO(
|
||||
cc->policyContext->logger, UA_LOGCATEGORY_SECURITYPOLICY,
|
||||
"The EccNistP256 security policy channel with openssl is deleted.");
|
||||
UA_free(cc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Compares the supplied certificate with the certificate
|
||||
* in the endpoint context
|
||||
*/
|
||||
|
||||
static UA_StatusCode
|
||||
UA_compareCertificateThumbprint_EccNistP256(const UA_SecurityPolicy *securityPolicy,
|
||||
const UA_ByteString *certificateThumbprint) {
|
||||
if(securityPolicy == NULL || certificateThumbprint == NULL) {
|
||||
return UA_STATUSCODE_BADINVALIDARGUMENT;
|
||||
}
|
||||
Policy_Context_EccNistP256 *pc =
|
||||
(Policy_Context_EccNistP256 *)securityPolicy->policyContext;
|
||||
if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
|
||||
return UA_STATUSCODE_BADCERTIFICATEINVALID;
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
/* Generates a thumbprint for the specified certificate */
|
||||
|
||||
static UA_StatusCode
|
||||
UA_makeCertificateThumbprint_EccNistP256(const UA_SecurityPolicy *securityPolicy,
|
||||
const UA_ByteString *certificate,
|
||||
UA_ByteString *thumbprint) {
|
||||
return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_Asym_EccNistP256_getRemoteSignatureSize(const void *channelContext) {
|
||||
if(channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
/* According to the standard, the server and the client must agree on the
|
||||
* security mode and security policy. Therefore, it can be assumed that
|
||||
* the remote asymmetric cryptographic tokens have the same sizes as the
|
||||
* local ones. */
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_AsySig_EccNistP256_getLocalSignatureSize(const void *channelContext) {
|
||||
if(channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_ASYM_SIGNATURE_LENGTH;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_AsymEn_EccNistP256_getRemotePlainTextBlockSize(const void *channelContext) {
|
||||
if(channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_AsymEn_EccNistP256_getRemoteBlockSize(const void *channelContext) {
|
||||
if(channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_AsymEn_EccNistP256_getRemoteKeyLength(const void *channelContext) {
|
||||
if(channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
/* According to the standard, the server and the client must agree on the
|
||||
* security mode and security policy. Therefore, it can be assumed that
|
||||
* the remote asymmetric cryptographic tokens have the same sizes as the
|
||||
* local ones.
|
||||
*
|
||||
* No ECC encryption -> key length set to 1 to avoid division or
|
||||
* multiplication with 0 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_Sym_EccNistP256_generateNonce(void *policyContext,
|
||||
UA_ByteString *out) {
|
||||
|
||||
Policy_Context_EccNistP256* pctx =
|
||||
(Policy_Context_EccNistP256 *) policyContext;
|
||||
|
||||
if(pctx == NULL) {
|
||||
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||
}
|
||||
|
||||
if (out->length == UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES) {
|
||||
if (UA_OpenSSL_ECC_NISTP256_GenerateKey(&pctx->channelContext->localEphemeralKeyPair, out) != UA_STATUSCODE_GOOD) {
|
||||
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||
}
|
||||
} else {
|
||||
UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
|
||||
if(rc != 1) {
|
||||
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymEn_EccNistP256_getLocalKeyLength(const void *channelContext) {
|
||||
/* 32 bytes 256 bits */
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymSig_EccNistP256_getLocalKeyLength(const void *channelContext) {
|
||||
/* 32 bytes 256 bits */
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_Sym_EccNistP256_generateKey(void *policyContext,
|
||||
const UA_ByteString *key1,
|
||||
const UA_ByteString *key2,
|
||||
UA_ByteString *out
|
||||
) {
|
||||
|
||||
Policy_Context_EccNistP256* pctx =
|
||||
(Policy_Context_EccNistP256 *) policyContext;
|
||||
|
||||
if(pctx == NULL) {
|
||||
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||
}
|
||||
|
||||
return UA_OpenSSL_ECC_DeriveKeys(EC_curve_nist2nid("P-256"), "SHA256",
|
||||
pctx->applicationType,
|
||||
pctx->channelContext->localEphemeralKeyPair,
|
||||
key1, key2, out);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelModule_EccNistP256_setLocalSymSigningKey(void *channelContext,
|
||||
const UA_ByteString *key) {
|
||||
if(key == NULL || channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_ByteString_clear(&cc->localSymSigningKey);
|
||||
return UA_ByteString_copy(key, &cc->localSymSigningKey);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelM_EccNistP256_setLocalSymEncryptingKey(void *channelContext,
|
||||
const UA_ByteString *key) {
|
||||
if(key == NULL || channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_ByteString_clear(&cc->localSymEncryptingKey);
|
||||
return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelM_EccNistP256_setLocalSymIv(void *channelContext,
|
||||
const UA_ByteString *iv) {
|
||||
if(iv == NULL || channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_ByteString_clear(&cc->localSymIv);
|
||||
return UA_ByteString_copy(iv, &cc->localSymIv);
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymEn_EccNistP256_getRemoteKeyLength(const void *channelContext) {
|
||||
/* 32 bytes 256 bits */
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_KEY_LENGTH;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymEn_EccNistP256_getBlockSize(const void *channelContext) {
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_SYM_ENCRYPTION_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymSig_EccNistP256_getRemoteKeyLength(const void *channelContext) {
|
||||
/* 32 bytes 256 bits */
|
||||
return UA_SECURITYPOLICY_ECCNISTP256_SYM_SIGNING_KEY_LENGTH;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelM_EccNistP256_setRemoteSymSigningKey(void *channelContext,
|
||||
const UA_ByteString *key) {
|
||||
if(key == NULL || channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_ByteString_clear(&cc->remoteSymSigningKey);
|
||||
return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelM_EccNistP256_setRemoteSymEncryptingKey(void *channelContext,
|
||||
const UA_ByteString *key) {
|
||||
if(key == NULL || channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_ByteString_clear(&cc->remoteSymEncryptingKey);
|
||||
return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelM_EccNistP256_setRemoteSymIv(void *channelContext,
|
||||
const UA_ByteString *key) {
|
||||
if(key == NULL || channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_ByteString_clear(&cc->remoteSymIv);
|
||||
return UA_ByteString_copy(key, &cc->remoteSymIv);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_AsymSig_EccNistP256_sign(void *channelContext, const UA_ByteString *message,
|
||||
UA_ByteString *signature) {
|
||||
if(channelContext == NULL || message == NULL ||
|
||||
signature == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc = (Channel_Context_EccNistP256 *)channelContext;
|
||||
Policy_Context_EccNistP256 *pc = cc->policyContext;
|
||||
|
||||
UA_StatusCode retval = UA_Openssl_ECDSA_SHA256_Sign(message, pc->localPrivateKey, signature);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static UA_StatusCode
|
||||
UA_AsymSig_EccNistP256_verify(void *channelContext, const UA_ByteString *message,
|
||||
const UA_ByteString *signature) {
|
||||
if(message == NULL || signature == NULL || channelContext == NULL) {
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
}
|
||||
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
UA_StatusCode retval = UA_Openssl_ECDSA_SHA256_Verify(
|
||||
message, cc->remoteCertificateX509, signature);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_Asym_EccNistP256_Dummy(void *channelContext, UA_ByteString *data) {
|
||||
/* Do nothing and return true */
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymSig_EccNistP256_getRemoteSignatureSize(const void *channelContext) {
|
||||
return UA_SHA256_LENGTH;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_SymSig_EccNistP256_verify(void *channelContext, const UA_ByteString *message,
|
||||
const UA_ByteString *signature) {
|
||||
if(channelContext == NULL || message == NULL ||
|
||||
signature == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_SymSig_EccNistP256_sign(void *channelContext, const UA_ByteString *message,
|
||||
UA_ByteString *signature) {
|
||||
if(channelContext == NULL || message == NULL ||
|
||||
signature == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_SymSig_EccNistP256_getLocalSignatureSize(const void *channelContext) {
|
||||
return UA_SHA256_LENGTH;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_SymEn_EccNistP256_decrypt(void *channelContext, UA_ByteString *data) {
|
||||
if(channelContext == NULL || data == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
|
||||
data);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_SymEn_EccNistP256_encrypt(void *channelContext, UA_ByteString *data) {
|
||||
if(channelContext == NULL || data == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
Channel_Context_EccNistP256 *cc =
|
||||
(Channel_Context_EccNistP256 *)channelContext;
|
||||
return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
|
||||
data);
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_ChannelM_EccNistP256_compareCertificate(const void *channelContext,
|
||||
const UA_ByteString *certificate) {
|
||||
if(channelContext == NULL || certificate == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
const Channel_Context_EccNistP256 *cc = (const Channel_Context_EccNistP256 *)channelContext;
|
||||
return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
|
||||
}
|
||||
|
||||
static size_t
|
||||
UA_AsymEn_EccNistP256_getLocalKeyLength(const void *channelContext) {
|
||||
if(channelContext == NULL)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
/* No ECC encryption -> key length set to 1 to avoid division or
|
||||
* multiplication with 0 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* the main entry of EccNistP256 */
|
||||
|
||||
UA_StatusCode
|
||||
UA_SecurityPolicy_EccNistP256(UA_SecurityPolicy *policy,
|
||||
const UA_ApplicationType applicationType,
|
||||
const UA_ByteString localCertificate,
|
||||
const UA_ByteString localPrivateKey,
|
||||
const UA_Logger *logger) {
|
||||
|
||||
UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
|
||||
UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
|
||||
UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;
|
||||
UA_StatusCode retval;
|
||||
|
||||
UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURITYPOLICY,
|
||||
"The EccNistP256 security policy with openssl is added.");
|
||||
|
||||
UA_Openssl_Init();
|
||||
memset(policy, 0, sizeof(UA_SecurityPolicy));
|
||||
policy->logger = logger;
|
||||
policy->policyUri =
|
||||
UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256\0");
|
||||
policy->securityLevel = 10;
|
||||
|
||||
/* set ChannelModule context */
|
||||
|
||||
channelModule->newContext = UA_ChannelModule_EccNistP256_New_Context;
|
||||
channelModule->deleteContext = UA_ChannelModule_EccNistP256_Delete_Context;
|
||||
channelModule->setLocalSymSigningKey =
|
||||
UA_ChannelModule_EccNistP256_setLocalSymSigningKey;
|
||||
channelModule->setLocalSymEncryptingKey =
|
||||
UA_ChannelM_EccNistP256_setLocalSymEncryptingKey;
|
||||
channelModule->setLocalSymIv = UA_ChannelM_EccNistP256_setLocalSymIv;
|
||||
channelModule->setRemoteSymSigningKey =
|
||||
UA_ChannelM_EccNistP256_setRemoteSymSigningKey;
|
||||
channelModule->setRemoteSymEncryptingKey =
|
||||
UA_ChannelM_EccNistP256_setRemoteSymEncryptingKey;
|
||||
channelModule->setRemoteSymIv = UA_ChannelM_EccNistP256_setRemoteSymIv;
|
||||
channelModule->compareCertificate =
|
||||
UA_ChannelM_EccNistP256_compareCertificate;
|
||||
|
||||
/* Copy the certificate and add a NULL to the end */
|
||||
|
||||
retval = UA_copyCertificate(&policy->localCertificate, &localCertificate);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
|
||||
/* AsymmetricModule - signature algorithm */
|
||||
|
||||
UA_SecurityPolicySignatureAlgorithm *asySigAlgorithm =
|
||||
&asymmetricModule->cryptoModule.signatureAlgorithm;
|
||||
asySigAlgorithm->uri =
|
||||
UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2473\0");
|
||||
asySigAlgorithm->verify = UA_AsymSig_EccNistP256_verify;
|
||||
asySigAlgorithm->getRemoteSignatureSize =
|
||||
UA_Asym_EccNistP256_getRemoteSignatureSize;
|
||||
asySigAlgorithm->getLocalSignatureSize =
|
||||
UA_AsySig_EccNistP256_getLocalSignatureSize;
|
||||
asySigAlgorithm->sign = UA_AsymSig_EccNistP256_sign;
|
||||
asySigAlgorithm->getLocalKeyLength = NULL;
|
||||
asySigAlgorithm->getRemoteKeyLength = NULL;
|
||||
|
||||
/* AsymmetricModule encryption algorithm */
|
||||
|
||||
UA_SecurityPolicyEncryptionAlgorithm *asymEncryAlg =
|
||||
&asymmetricModule->cryptoModule.encryptionAlgorithm;
|
||||
asymEncryAlg->uri = UA_STRING("https://profiles.opcfoundation.org/conformanceunit/2720\0");
|
||||
asymEncryAlg->getRemotePlainTextBlockSize =
|
||||
UA_AsymEn_EccNistP256_getRemotePlainTextBlockSize;
|
||||
asymEncryAlg->getRemoteBlockSize = UA_AsymEn_EccNistP256_getRemoteBlockSize;
|
||||
asymEncryAlg->getRemoteKeyLength = UA_AsymEn_EccNistP256_getRemoteKeyLength;
|
||||
asymEncryAlg->encrypt = UA_Asym_EccNistP256_Dummy;
|
||||
asymEncryAlg->decrypt = UA_Asym_EccNistP256_Dummy;
|
||||
asymEncryAlg->getLocalKeyLength = UA_AsymEn_EccNistP256_getLocalKeyLength;
|
||||
|
||||
/* asymmetricModule */
|
||||
|
||||
asymmetricModule->compareCertificateThumbprint =
|
||||
UA_compareCertificateThumbprint_EccNistP256;
|
||||
asymmetricModule->makeCertificateThumbprint =
|
||||
UA_makeCertificateThumbprint_EccNistP256;
|
||||
|
||||
/* SymmetricModule */
|
||||
|
||||
symmetricModule->secureChannelNonceLength = UA_SECURITYPOLICY_ECCNISTP256_NONCE_LENGTH_BYTES;
|
||||
symmetricModule->generateNonce = UA_Sym_EccNistP256_generateNonce;
|
||||
symmetricModule->generateKey = UA_Sym_EccNistP256_generateKey;
|
||||
|
||||
/* Symmetric encryption Algorithm */
|
||||
|
||||
UA_SecurityPolicyEncryptionAlgorithm *symEncryptionAlgorithm =
|
||||
&symmetricModule->cryptoModule.encryptionAlgorithm;
|
||||
symEncryptionAlgorithm->uri =
|
||||
UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
|
||||
symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_EccNistP256_getLocalKeyLength;
|
||||
symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_EccNistP256_getRemoteKeyLength;
|
||||
symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_EccNistP256_getBlockSize;
|
||||
symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_EccNistP256_getBlockSize;
|
||||
symEncryptionAlgorithm->decrypt = UA_SymEn_EccNistP256_decrypt;
|
||||
symEncryptionAlgorithm->encrypt = UA_SymEn_EccNistP256_encrypt;
|
||||
|
||||
/* Symmetric signature Algorithm */
|
||||
|
||||
UA_SecurityPolicySignatureAlgorithm *symSignatureAlgorithm =
|
||||
&symmetricModule->cryptoModule.signatureAlgorithm;
|
||||
symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
|
||||
symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_EccNistP256_getLocalKeyLength;
|
||||
symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_EccNistP256_getRemoteKeyLength;
|
||||
symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_EccNistP256_getRemoteSignatureSize;
|
||||
symSignatureAlgorithm->verify = UA_SymSig_EccNistP256_verify;
|
||||
symSignatureAlgorithm->sign = UA_SymSig_EccNistP256_sign;
|
||||
symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_EccNistP256_getLocalSignatureSize;
|
||||
|
||||
retval = UA_Policy_EccNistP256_New_Context(policy, localPrivateKey, applicationType, logger);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_ByteString_clear(&policy->localCertificate);
|
||||
return retval;
|
||||
}
|
||||
policy->updateCertificateAndPrivateKey =
|
||||
updateCertificateAndPrivateKey_sp_EccNistP256;
|
||||
policy->createSigningRequest = createSigningRequest_sp_eccnistp256;
|
||||
policy->clear = UA_Policy_EccNistP256_Clear_Context;
|
||||
|
||||
/* Use the same signature algorithm as the asymmetric component for
|
||||
certificate signing (see standard) */
|
||||
|
||||
policy->certificateSigningAlgorithm =
|
||||
policy->asymmetricModule.cryptoModule.signatureAlgorithm;
|
||||
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
|
||||
* Copyright 2017 (c) Stefan Profanter, fortiss GmbH
|
||||
* Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
|
||||
* Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
|
||||
*/
|
||||
|
||||
#ifndef UA_SECURITYPOLICIES_H_
|
||||
@ -50,6 +51,13 @@ UA_SecurityPolicy_Aes256Sha256RsaPss(UA_SecurityPolicy *policy,
|
||||
const UA_ByteString localPrivateKey,
|
||||
const UA_Logger *logger);
|
||||
|
||||
UA_EXPORT UA_StatusCode
|
||||
UA_SecurityPolicy_EccNistP256(UA_SecurityPolicy *policy,
|
||||
const UA_ApplicationType applicationType,
|
||||
const UA_ByteString localCertificate,
|
||||
const UA_ByteString localPrivateKey,
|
||||
const UA_Logger *logger);
|
||||
|
||||
#ifdef __linux__ /* Linux only so far */
|
||||
UA_EXPORT UA_StatusCode
|
||||
UA_SecurityPolicy_Filestore(UA_SecurityPolicy *policy,
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright 2017 (c) Stefan Profanter, fortiss GmbH
|
||||
* Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
|
||||
* Copyright 2019 (c) Kalycito Infotech Private Limited
|
||||
* Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
|
||||
*/
|
||||
|
||||
#ifndef UA_SERVER_CONFIG_DEFAULT_H_
|
||||
@ -221,6 +222,21 @@ UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(UA_ServerConfig *config,
|
||||
const UA_ByteString *certificate,
|
||||
const UA_ByteString *privateKey);
|
||||
|
||||
/* Adds the security policy ``SecurityPolicy#EccNistP256`` to the server. A
|
||||
* server certificate may be supplied but is optional.
|
||||
*
|
||||
* Certificate verification should be configured before calling this
|
||||
* function. See PKI plugin.
|
||||
*
|
||||
* @param config The configuration to manipulate
|
||||
* @param certificate The server certificate.
|
||||
* @param privateKey The private key that corresponds to the certificate.
|
||||
*/
|
||||
UA_EXPORT UA_StatusCode
|
||||
UA_ServerConfig_addSecurityPolicyEccNistP256(UA_ServerConfig *config,
|
||||
const UA_ByteString *certificate,
|
||||
const UA_ByteString *privateKey);
|
||||
|
||||
/* Adds all supported security policies and sets up certificate
|
||||
* validation procedures.
|
||||
*
|
||||
|
@ -11,6 +11,7 @@
|
||||
* Copyright 2019 (c) Kalycito Infotech Private Limited
|
||||
* Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
|
||||
* Copyright 2020 (c) Wind River Systems, Inc.
|
||||
* Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
|
||||
*/
|
||||
|
||||
#include <open62541/client.h>
|
||||
@ -209,7 +210,7 @@ const UA_ConnectionConfig UA_ConnectionConfig_default = {
|
||||
#define APPLICATION_URI "urn:unconfigured:application"
|
||||
#define APPLICATION_URI_SERVER "urn:open62541.server.application"
|
||||
|
||||
#define SECURITY_POLICY_SIZE 6
|
||||
#define SECURITY_POLICY_SIZE 7
|
||||
|
||||
#define STRINGIFY(arg) #arg
|
||||
#define VERSION(MAJOR, MINOR, PATCH, LABEL) \
|
||||
@ -855,6 +856,43 @@ UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(UA_ServerConfig *config,
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
UA_EXPORT UA_StatusCode
|
||||
UA_ServerConfig_addSecurityPolicyEccNistP256(UA_ServerConfig *config,
|
||||
const UA_ByteString *certificate,
|
||||
const UA_ByteString *privateKey) {
|
||||
/* Allocate the SecurityPolicies */
|
||||
UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
|
||||
UA_realloc(config->securityPolicies,
|
||||
sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
|
||||
if(!tmp)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
config->securityPolicies = tmp;
|
||||
|
||||
/* Populate the SecurityPolicies */
|
||||
UA_ByteString localCertificate = UA_BYTESTRING_NULL;
|
||||
UA_ByteString localPrivateKey = UA_BYTESTRING_NULL;
|
||||
if(certificate)
|
||||
localCertificate = *certificate;
|
||||
if(privateKey)
|
||||
localPrivateKey = *privateKey;
|
||||
UA_StatusCode retval =
|
||||
UA_SecurityPolicy_EccNistP256(&config->securityPolicies[config->securityPoliciesSize],
|
||||
UA_APPLICATIONTYPE_SERVER, localCertificate,
|
||||
localPrivateKey, config->logging);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
if(config->securityPoliciesSize == 0) {
|
||||
UA_free(config->securityPolicies);
|
||||
config->securityPolicies = NULL;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
config->securityPoliciesSize++;
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Always returns UA_STATUSCODE_GOOD. Logs a warning if policies could not be added. */
|
||||
static UA_StatusCode
|
||||
addAllSecurityPolicies(UA_ServerConfig *config, const UA_ByteString *certificate,
|
||||
@ -954,6 +992,17 @@ addAllSecurityPolicies(UA_ServerConfig *config, const UA_ByteString *certificate
|
||||
/* UA_StatusCode_name(retval)); */
|
||||
/* } */
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
/* EccNistP256 */
|
||||
retval = UA_ServerConfig_addSecurityPolicyEccNistP256(config, &localCertificate,
|
||||
&decryptedPrivateKey);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"Could not add SecurityPolicy#EccNistP256 with error code %s",
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
#endif
|
||||
|
||||
UA_ByteString_memZero(&decryptedPrivateKey);
|
||||
UA_ByteString_clear(&decryptedPrivateKey);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
@ -1441,6 +1490,34 @@ UA_ServerConfig_addSecurityPolicies_Filestore(UA_ServerConfig *config,
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
/* EccNistP256 */
|
||||
UA_SecurityPolicy *eccnistp256Policy =
|
||||
(UA_SecurityPolicy*)UA_calloc(1, sizeof(UA_SecurityPolicy));
|
||||
if(!eccnistp256Policy) {
|
||||
UA_ByteString_memZero(&decryptedPrivateKey);
|
||||
UA_ByteString_clear(&decryptedPrivateKey);
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
retval = UA_SecurityPolicy_EccNistP256(eccnistp256Policy, UA_APPLICATIONTYPE_SERVER,
|
||||
localCertificate, decryptedPrivateKey,
|
||||
config->logging);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"Could not add SecurityPolicy#ECC_nistP256 with error code %s",
|
||||
UA_StatusCode_name(retval));
|
||||
eccnistp256Policy->clear(eccnistp256Policy);
|
||||
UA_free(eccnistp256Policy);
|
||||
eccnistp256Policy = NULL;
|
||||
}
|
||||
retval = UA_ServerConfig_addSecurityPolicy_Filestore(config, eccnistp256Policy, storePath);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"Could not add SecurityPolicy#ECC_nistP256 with error code %s",
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
#endif
|
||||
|
||||
UA_ByteString_memZero(&decryptedPrivateKey);
|
||||
UA_ByteString_clear(&decryptedPrivateKey);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
@ -1503,6 +1580,11 @@ UA_ServerConfig_setDefaultWithFilestore(UA_ServerConfig *conf,
|
||||
/***************************/
|
||||
/* Default Client Settings */
|
||||
/***************************/
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
#define AUTH_SECURITY_POLICY_SIZE 4
|
||||
#else
|
||||
#define AUTH_SECURITY_POLICY_SIZE 3
|
||||
#endif
|
||||
|
||||
UA_Client * UA_Client_new(void) {
|
||||
UA_ClientConfig config;
|
||||
@ -1625,7 +1707,7 @@ clientConfig_setAuthenticationSecurityPolicies(UA_ClientConfig *config,
|
||||
UA_ByteString certificateAuth,
|
||||
UA_ByteString privateKeyAuth) {
|
||||
UA_SecurityPolicy *sp = (UA_SecurityPolicy*)
|
||||
UA_realloc(config->authSecurityPolicies, sizeof(UA_SecurityPolicy) * 3);
|
||||
UA_realloc(config->authSecurityPolicies, sizeof(UA_SecurityPolicy) * AUTH_SECURITY_POLICY_SIZE);
|
||||
if(!sp)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
config->authSecurityPolicies = sp;
|
||||
@ -1689,6 +1771,18 @@ clientConfig_setAuthenticationSecurityPolicies(UA_ClientConfig *config,
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
sp = &config->authSecurityPolicies[config->authSecurityPoliciesSize];
|
||||
retval = UA_SecurityPolicy_EccNistP256(sp, UA_APPLICATIONTYPE_CLIENT, certificateAuth, privateKeyAuth, config->logging);
|
||||
if(retval == UA_STATUSCODE_GOOD) {
|
||||
++config->authSecurityPoliciesSize;
|
||||
} else {
|
||||
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"Could not add SecurityPolicy#EccNistP256 with error code %s",
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
#endif
|
||||
|
||||
if(config->authSecurityPoliciesSize == 0) {
|
||||
UA_free(config->authSecurityPolicies);
|
||||
config->authSecurityPolicies = NULL;
|
||||
@ -1837,6 +1931,19 @@ UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config,
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
|
||||
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL)
|
||||
retval = UA_SecurityPolicy_EccNistP256(&config->securityPolicies[config->securityPoliciesSize],
|
||||
UA_APPLICATIONTYPE_CLIENT, localCertificate,
|
||||
decryptedPrivateKey, config->logging);
|
||||
if(retval == UA_STATUSCODE_GOOD) {
|
||||
++config->securityPoliciesSize;
|
||||
} else {
|
||||
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
|
||||
"Could not add SecurityPolicy#EccNistP256 with error code %s",
|
||||
UA_StatusCode_name(retval));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the same certificate also for authentication.
|
||||
* Can be overridden with a different certificate. */
|
||||
if(config->authSecurityPoliciesSize == 0)
|
||||
|
Loading…
Reference in New Issue
Block a user