Skip to content

Commit

Permalink
feat(server): Enable x509 certificate authentication in the server co…
Browse files Browse the repository at this point in the history
…nfig
  • Loading branch information
jpfr committed Sep 24, 2021
1 parent cb93576 commit 2c87f1e
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 12 deletions.
2 changes: 1 addition & 1 deletion examples/access_control/server_access_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ int main(void) {

/* Disable anonymous logins, enable two user/password logins */
config->accessControl.clear(&config->accessControl);
UA_StatusCode retval = UA_AccessControl_default(config, false,
UA_StatusCode retval = UA_AccessControl_default(config, false, NULL,
&config->securityPolicies[config->securityPoliciesSize-1].policyUri, 2, logins);
if(retval != UA_STATUSCODE_GOOD)
goto cleanup;
Expand Down
8 changes: 7 additions & 1 deletion plugins/crypto/openssl/ua_pki_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,13 @@ UA_CertificateVerification_CertFolders(UA_CertificateVerification * cv,
cv->verifyApplicationURI = UA_CertificateVerification_VerifyApplicationURI;
cv->clear = UA_CertificateVerification_clear;
cv->context = context;
cv->verifyCertificate = UA_CertificateVerification_Verify;
if(trustListFolder == NULL &&
issuerListFolder == NULL &&
revocationListFolder == NULL) {
cv->verifyCertificate = UA_VerifyCertificateAllowAll;
} else {
cv->verifyCertificate = UA_CertificateVerification_Verify;
}

/* Only set the folder paths. They will be reloaded during runtime. */

Expand Down
9 changes: 7 additions & 2 deletions plugins/include/open62541/plugin/accesscontrol_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ typedef struct {
} UA_UsernamePasswordLogin;

/* Default access control. The log-in can be anonymous or username-password. A
* logged-in user has all access rights. */
* logged-in user has all access rights.
*
* The certificate verification plugin lifecycle is moved to the access control
* system. So it is cleared up eventually together with the AccessControl. */
UA_EXPORT UA_StatusCode
UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous,
UA_AccessControl_default(UA_ServerConfig *config,
UA_Boolean allowAnonymous,
UA_CertificateVerification *verifyX509,
const UA_ByteString *userTokenPolicyUri,
size_t usernamePasswordLoginSize,
const UA_UsernamePasswordLogin *usernamePasswordLogin);
Expand Down
55 changes: 51 additions & 4 deletions plugins/ua_accesscontrol_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ typedef struct {
UA_Boolean allowAnonymous;
size_t usernamePasswordLoginSize;
UA_UsernamePasswordLogin *usernamePasswordLogin;
UA_CertificateVerification verifyX509;
} AccessControlContext;

#define ANONYMOUS_POLICY "open62541-anonymous-policy"
#define CERTIFICATE_POLICY "open62541-certificate-policy"
#define USERNAME_POLICY "open62541-username-policy"
const UA_String anonymous_policy = UA_STRING_STATIC(ANONYMOUS_POLICY);
const UA_String certificate_policy = UA_STRING_STATIC(CERTIFICATE_POLICY);
const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY);

/************************/
Expand Down Expand Up @@ -110,6 +113,22 @@ activateSession_default(UA_Server *server, UA_AccessControl *ac,
return UA_STATUSCODE_GOOD;
}

/* x509 certificate */
if(userIdentityToken->content.decoded.type == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
const UA_X509IdentityToken *userToken = (UA_X509IdentityToken*)
userIdentityToken->content.decoded.data;

if(!UA_String_equal(&userToken->policyId, &certificate_policy))
return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

if(!context->verifyX509.verifyCertificate)
return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

return context->verifyX509.
verifyCertificate(context->verifyX509.context,
&userToken->certificateData);
}

/* Unsupported token type */
return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
}
Expand Down Expand Up @@ -240,21 +259,27 @@ static void clear_default(UA_AccessControl *ac) {
}
if(context->usernamePasswordLoginSize > 0)
UA_free(context->usernamePasswordLogin);

if(context->verifyX509.clear)
context->verifyX509.clear(&context->verifyX509);

UA_free(ac->context);
ac->context = NULL;
}
}

UA_StatusCode
UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous,
UA_AccessControl_default(UA_ServerConfig *config,
UA_Boolean allowAnonymous,
UA_CertificateVerification *verifyX509,
const UA_ByteString *userTokenPolicyUri,
size_t usernamePasswordLoginSize,
const UA_UsernamePasswordLogin *usernamePasswordLogin) {
UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_SERVER,
"AccessControl: Unconfigured AccessControl. Users have all permissions.");
UA_AccessControl *ac = &config->accessControl;

if (ac->clear)
if(ac->clear)
clear_default(ac);

ac->clear = clear_default;
Expand Down Expand Up @@ -294,6 +319,16 @@ UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous,
"AccessControl: Anonymous login is enabled");
}

/* Allow x509 certificates? Move the plugin over. */
if(verifyX509) {
context->verifyX509 = *verifyX509;
memset(verifyX509, 0, sizeof(UA_CertificateVerification));
} else {
memset(&context->verifyX509, 0, sizeof(UA_CertificateVerification));
UA_LOG_INFO(&config->logger, UA_LOGCATEGORY_SERVER,
"AccessControl: x509 certificate user authentication is enabled");
}

/* Copy username/password to the access control plugin */
if(usernamePasswordLoginSize > 0) {
context->usernamePasswordLogin = (UA_UsernamePasswordLogin*)
Expand All @@ -302,15 +337,19 @@ UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous,
return UA_STATUSCODE_BADOUTOFMEMORY;
context->usernamePasswordLoginSize = usernamePasswordLoginSize;
for(size_t i = 0; i < usernamePasswordLoginSize; i++) {
UA_String_copy(&usernamePasswordLogin[i].username, &context->usernamePasswordLogin[i].username);
UA_String_copy(&usernamePasswordLogin[i].password, &context->usernamePasswordLogin[i].password);
UA_String_copy(&usernamePasswordLogin[i].username,
&context->usernamePasswordLogin[i].username);
UA_String_copy(&usernamePasswordLogin[i].password,
&context->usernamePasswordLogin[i].password);
}
}

/* Set the allowed policies */
size_t policies = 0;
if(allowAnonymous)
policies++;
if(verifyX509)
policies++;
if(usernamePasswordLoginSize > 0)
policies++;
ac->userTokenPoliciesSize = 0;
Expand All @@ -329,6 +368,14 @@ UA_AccessControl_default(UA_ServerConfig *config, UA_Boolean allowAnonymous,
policies++;
}

if(verifyX509) {
ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_CERTIFICATE;
ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(CERTIFICATE_POLICY);
if (!ac->userTokenPolicies[policies].policyId.data)
return UA_STATUSCODE_BADOUTOFMEMORY;
policies++;
}

if(usernamePasswordLoginSize > 0) {
ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME;
ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
Expand Down
13 changes: 9 additions & 4 deletions plugins/ua_config_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,9 @@ UA_ServerConfig_setMinimalCustomBuffer(UA_ServerConfig *config, UA_UInt16 portNu
}

/* Initialize the Access Control plugin */
retval = UA_AccessControl_default(config, true,
&config->securityPolicies[config->securityPoliciesSize-1].policyUri,
usernamePasswordsSize, usernamePasswords);
retval = UA_AccessControl_default(config, true, NULL,
&config->securityPolicies[config->securityPoliciesSize-1].policyUri,
usernamePasswordsSize, usernamePasswords);
if(retval != UA_STATUSCODE_GOOD) {
UA_ServerConfig_clean(config);
return retval;
Expand Down Expand Up @@ -704,7 +704,12 @@ UA_ServerConfig_setDefaultWithSecurityPolicies(UA_ServerConfig *conf,
return retval;
}

retval = UA_AccessControl_default(conf, true,
UA_CertificateVerification accessControlVerification;
retval = UA_CertificateVerification_Trustlist(&accessControlVerification,
trustList, trustListSize,
issuerList, issuerListSize,
revocationList, revocationListSize);
retval |= UA_AccessControl_default(conf, true, &accessControlVerification,
&conf->securityPolicies[conf->securityPoliciesSize-1].policyUri,
usernamePasswordsSize, usernamePasswords);
if(retval != UA_STATUSCODE_GOOD) {
Expand Down

0 comments on commit 2c87f1e

Please sign in to comment.