#include <open62541/types.h>
#include "ua_server_internal.h"
#include "ua_services.h"
UA_StatusCode
processOPN_AsymHeader(void *application, UA_SecureChannel *channel,
const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
if(channel->securityPolicy)
return UA_STATUSCODE_GOOD;
UA_Server *server = (UA_Server *)application;
UA_ServerConfig *sc = &server->config;
UA_SecurityPolicy *securityPolicy = NULL;
for(size_t i = 0; i < sc->securityPoliciesSize; ++i) {
UA_SecurityPolicy *policy = &sc->securityPolicies[i];
if(!UA_String_equal(&asymHeader->securityPolicyUri, &policy->policyUri))
continue;
UA_StatusCode res = policy->
compareCertThumbprint(policy, &asymHeader->receiverCertificateThumbprint);
if(res != UA_STATUSCODE_GOOD)
continue;
securityPolicy = policy;
break;
}
if(!securityPolicy)
return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
if(asymHeader->senderCertificate.length > 0) {
UA_StatusCode res =
validateCertificate(server, &sc->secureChannelPKI, channel, NULL,
"OpenSecureChannel", NULL, asymHeader->senderCertificate);
UA_CHECK_STATUS(res, return res);
}
UA_ByteString appInstCert = getLeafCertificate(asymHeader->senderCertificate);
return UA_SecureChannel_setSecurityPolicy(channel, securityPolicy, &appInstCert);
}
void
Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel *channel,
UA_OpenSecureChannelRequest *request,
UA_OpenSecureChannelResponse *response) {
UA_ServerConfig *sc = &server->config;
UA_EventLoop *el = server->config.eventLoop;
const UA_SecurityPolicy *sp = channel->securityPolicy;
switch(request->requestType) {
case UA_SECURITYTOKENREQUESTTYPE_ISSUE: {
if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT) {
UA_LOG_ERROR_CHANNEL(sc->logging, channel,
"OpenSecureChannel: Cannot open "
"already open or closed channel");
response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
return;
}
if(request->securityMode > UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
request->securityMode = UA_MESSAGESECURITYMODE_INVALID;
response->responseHeader.serviceResult =
UA_SecureChannel_setSecurityMode(channel, request->securityMode);
if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR_CHANNEL(sc->logging, channel,
"OpenSecureChannel: Client tries mismatching "
"SecurityMode %s for SecurityPolicy %S",
securityModeNames[request->securityMode],
sp->policyUri);
return;
}
break;
}
case UA_SECURITYTOKENREQUESTTYPE_RENEW:
if(channel->state != UA_SECURECHANNELSTATE_OPEN) {
UA_LOG_ERROR_CHANNEL(sc->logging, channel,
"OpenSecureChannel: The client called renew on "
"channel which is not open");
response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
return;
}
if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE &&
UA_ByteString_equal(&channel->remoteNonce, &request->clientNonce)) {
UA_LOG_ERROR_CHANNEL(sc->logging, channel,
"OpenSecureChannel: The client called renew "
"reusing the previous nonce");
response->responseHeader.serviceResult =
UA_STATUSCODE_BADSECURITYCHECKSFAILED;
return;
}
break;
default:
UA_LOG_ERROR_CHANNEL(sc->logging, channel,
"OpenSecureChannel: Unknown request type");
response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
return;
}
channel->altSecurityToken.channelId = channel->securityToken.channelId;
channel->altSecurityToken.tokenId = server->lastTokenId++;
channel->altSecurityToken.createdAt = el->dateTime_nowMonotonic(el);
channel->altSecurityToken.revisedLifetime =
(request->requestedLifetime > sc->maxSecurityTokenLifetime) ?
sc->maxSecurityTokenLifetime : request->requestedLifetime;
if(channel->altSecurityToken.revisedLifetime == 0)
channel->altSecurityToken.revisedLifetime =
sc->maxSecurityTokenLifetime;
UA_ByteString_clear(&channel->remoteNonce);
channel->remoteNonce = request->clientNonce;
UA_ByteString_init(&request->clientNonce);
response->responseHeader.serviceResult = UA_SecureChannel_generateLocalNonce(channel);
if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR_CHANNEL(sc->logging, channel,
"OpenSecureChannel: Cannot generate the local nonce");
return;
}
channel->renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER;
channel->state = UA_SECURECHANNELSTATE_OPEN;
response->securityToken = channel->altSecurityToken;
response->securityToken.createdAt = el->dateTime_now(el);
response->responseHeader.timestamp = response->securityToken.createdAt;
response->responseHeader.requestHandle = request->requestHeader.requestHandle;
response->responseHeader.serviceResult =
UA_ByteString_copy(&channel->localNonce, &response->serverNonce);
UA_CHECK_STATUS(response->responseHeader.serviceResult, return);
if(request->requestType == UA_SECURITYTOKENREQUESTTYPE_ISSUE) {
UA_LOG_INFO_CHANNEL(sc->logging, channel,
"OpenSecureChannel: Channel opened with SecurityMode %s for "
"SecurityPolicy %S and a revised lifetime of %.2fs",
securityModeNames[channel->securityMode],
channel->securityPolicy->policyUri,
(UA_Float)response->securityToken.revisedLifetime / 1000);
notifySecureChannel(server, channel,
UA_APPLICATIONNOTIFICATIONTYPE_SECURECHANNEL_OPENED);
} else {
UA_LOG_INFO_CHANNEL(sc->logging, channel,
"OpenSecureChannel: Channel renewed with a revised "
"lifetime of %.2fs",
(UA_Float)response->securityToken.revisedLifetime / 1000);
}
}
void
Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) {
UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
}
void
notifySecureChannel(UA_Server *server, UA_SecureChannel *channel,
UA_ApplicationNotificationType type) {
UA_ServerConfig *sc = &server->config;
if(!sc->globalNotificationCallback && !sc->secureChannelNotificationCallback)
return;
static UA_THREAD_LOCAL UA_KeyValuePair notifySCData[15] = {
{{0, UA_STRING_STATIC("securechannel-id")}, {0}},
{{0, UA_STRING_STATIC("connection-manager-name")}, {0}},
{{0, UA_STRING_STATIC("connection-id")}, {0}},
{{0, UA_STRING_STATIC("remote-address")}, {0}},
{{0, UA_STRING_STATIC("protocol-version")}, {0}},
{{0, UA_STRING_STATIC("recv-buffer-size")}, {0}},
{{0, UA_STRING_STATIC("recv-max-message-size")}, {0}},
{{0, UA_STRING_STATIC("recv-max-chunk-count")}, {0}},
{{0, UA_STRING_STATIC("send-buffer-size")}, {0}},
{{0, UA_STRING_STATIC("send-max-message-size")}, {0}},
{{0, UA_STRING_STATIC("send-max-chunk-count")}, {0}},
{{0, UA_STRING_STATIC("endpoint-url")}, {0}},
{{0, UA_STRING_STATIC("security-mode")}, {0}},
{{0, UA_STRING_STATIC("security-policy-url")}, {0}},
{{0, UA_STRING_STATIC("remote-certificate")}, {0}}
};
UA_KeyValueMap notifySCMap = {15, notifySCData};
UA_Variant_setScalar(¬ifySCData[0].value, &channel->securityToken.channelId,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[1].value,
&channel->connectionManager->eventSource.name,
&UA_TYPES[UA_TYPES_STRING]);
UA_UInt64 connectionId = channel->connectionId;
UA_Variant_setScalar(¬ifySCData[2].value, &connectionId,
&UA_TYPES[UA_TYPES_UINT64]);
UA_Variant_setScalar(¬ifySCData[3].value, &channel->remoteAddress,
&UA_TYPES[UA_TYPES_STRING]);
UA_Variant_setScalar(¬ifySCData[4].value, &channel->config.protocolVersion,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[5].value, &channel->config.recvBufferSize,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[6].value, &channel->config.localMaxMessageSize,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[7].value, &channel->config.localMaxChunkCount,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[8].value, &channel->config.sendBufferSize,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[9].value, &channel->config.remoteMaxMessageSize,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[10].value, &channel->config.remoteMaxChunkCount,
&UA_TYPES[UA_TYPES_UINT32]);
UA_Variant_setScalar(¬ifySCData[11].value, &channel->endpointUrl,
&UA_TYPES[UA_TYPES_STRING]);
UA_Variant_setScalar(¬ifySCData[12].value, &channel->securityMode,
&UA_TYPES[UA_TYPES_MESSAGESECURITYMODE]);
UA_String securityPolicyUri = UA_STRING_NULL;
if(channel->securityPolicy)
securityPolicyUri = channel->securityPolicy->policyUri;
UA_Variant_setScalar(¬ifySCData[13].value, &securityPolicyUri,
&UA_TYPES[UA_TYPES_STRING]);
UA_Variant_setScalar(¬ifySCData[14].value, &channel->remoteCertificate,
&UA_TYPES[UA_TYPES_BYTESTRING]);
if(sc->secureChannelNotificationCallback)
sc->secureChannelNotificationCallback(server, type, notifySCMap);
if(sc->globalNotificationCallback)
sc->globalNotificationCallback(server, type, notifySCMap);
}