Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client Certificate Authentication with R_usermap #371

Merged
merged 7 commits into from
Aug 11, 2023
Merged

Conversation

jordanfilteau1995
Copy link
Contributor

@jordanfilteau1995 jordanfilteau1995 commented Apr 5, 2023

Client certificate is grabbed from gsk after connection is established.

Signed-off-by: Jordan Filteau <[email protected]>
@jordanfilteau1995 jordanfilteau1995 changed the title [WIP] Client Certificate Authentication with R_usermap Client Certificate Authentication with R_usermap Apr 10, 2023
Signed-off-by: Jordan Filteau <[email protected]>
@ifakhrutdinov ifakhrutdinov self-requested a review April 12, 2023 15:22
@@ -109,8 +164,7 @@ int tlsSocketInit(TlsEnvironment *env, TlsSocket **outSocket, int fd, bool isSer
if (label) {
rc = rc || gsk_attribute_set_buffer(socket->socketHandle, GSK_KEYRING_LABEL, label, 0);
}
rc = rc || gsk_attribute_set_enum(socket->socketHandle, GSK_SESSION_TYPE,
isServer ? GSK_SERVER_SESSION : GSK_CLIENT_SESSION);
rc = rc || gsk_attribute_set_enum(socket->socketHandle, GSK_SESSION_TYPE, isServer ? GSK_SERVER_SESSION_WITH_CL_AUTH : GSK_CLIENT_SESSION);
Copy link
Contributor

@ifakhrutdinov ifakhrutdinov Apr 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we never be able to use this without a client certificate on the server side? Asking because it's either GSK_SERVER_SESSION_WITH_CL_AUTH or GSK_CLIENT_SESSION.

I can see cases where one would want to use this code just for a secure connection but without client authentication required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding and testing, it just allows client authentication to be an option if a client certificate is attached. It behaves the same way as usual if you don't provide a client certificate.

c/tls.c Outdated
@@ -123,6 +177,7 @@ int tlsSocketInit(TlsEnvironment *env, TlsSocket **outSocket, int fd, bool isSer
safeFree((char*)socket, sizeof(*socket));
*outSocket = NULL;
}
//printf("tlsSocketInit - rc=%d\n", rc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this.

c/tls.c Outdated

gsk_cert_data_elem *tmp = gskCertificateArray;

for (int i = 0; i++ < gskCertificateArrayElementCount; tmp++) {
Copy link
Contributor

@ifakhrutdinov ifakhrutdinov Apr 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not increment in a condition; this seems error prone.

What about this?

for (int i = 0; i < gskCertificateArrayElementCount; i++) {
  const gsk_cert_data_elem *elem = &gskCertificateArray[i];
  . . .
}

@ifakhrutdinov
Copy link
Contributor

@jordanfilteau1995 , please add a detailed description of these changes. I can see at least one change which isn't related to certificates. Hoe does the security logic changes?

Copy link
Contributor

@ifakhrutdinov ifakhrutdinov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let Jordan add a description before continuing with the review. For now, see my current comments.

@@ -15,6 +15,40 @@
#include "fdpoll.h"
#include "tls.h"

int getClientCertificate(gsk_handle soc_handle, char *clientCertificate, unsigned int clientCertificateBufferSize, unsigned int *clientCertificateLength) {

if (clientCertificate == NULL || clientCertificateBufferSize <= 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: clientCertificateBufferSize can't be less than 0.

if (tmp->cert_data_id == CERT_BODY_DER) {
if (clientCertificateBufferSize >= tmp->cert_data_l) {
memcpy(clientCertificate, tmp->cert_data_p, tmp->cert_data_l);
*clientCertificateLength = tmp->cert_data_l;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point we've copied the data and continue. Is it okay to overwrite it if one of the next array entries matches the condition or do we need to break here?

c/tls.c Outdated
@@ -43,13 +94,15 @@ int tlsInit(TlsEnvironment **outEnv, TlsSettings *settings) {
safeFree((char*)env, sizeof(*env));
*outEnv = NULL;
}
//printf("tlsInit - rc=%d\n", rc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clean up dead code.

c/tls.c Outdated
#endif

/*
* Only allow requests with client certificates, maybe put behind a different ifdef.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code?

c/tls.c Outdated
/*
* Don't validate certificates, maybe put behind a dangerous ifdef.
*
* rc = rc || gsk_attribute_set_enum(env->envHandle, GSK_CLIENT_AUTH_TYPE, GSK_CLIENT_AUTH_PASSTHRU_TYPE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code?

Comment on lines +2661 to +2672
printf("SAF auth for user: '%s'\n", request->username);
#else
printf("u: '%s' p: '%s'\n",request->username,request->password);
printf("u: '%s' p: '%s'\n",request->username,request->password);
#endif
#endif
if (isLowerCasePasswordAllowed() || isPassPhrase(request->password)) {
zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, "mixed-case system or a pass phrase, not upfolding password\n");
/* don't upfold password */
} else {
zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, "non-mixed-case system, not a pass phrase, upfolding password\n");
strupcase(request->password); /* upfold password */
if (isLowerCasePasswordAllowed() || isPassPhrase(request->password)) {
zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, "mixed-case system or a pass phrase, not upfolding password\n");
/* don't upfold password */
} else {
zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, "non-mixed-case system, not a pass phrase, upfolding password\n");
strupcase(request->password); /* upfold password */
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need these white space changes?

Comment on lines +2687 to +2692
} else {
pwdCheckRC = zisCheckUsername(privilegedServerName,
request->username, &status);
authResponse->type = AUTH_TYPE_RACF;
authResponse->responseDetails.safStatus = status.safStatus;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need more info about this and why we need this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irek, we need either a new API, or a new arg in the existing API to say if password is required.

c/httpserver.c Outdated
}
}

/* Doubtful that it would be greater than 8k... */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we know for sure? I.e. references to standards/docs would help here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the R_usermap doc for limits. Some 'net searching yielded 8K, blame me for this.

c/httpserver.c Outdated
@@ -2653,19 +2653,23 @@ static int safAuthenticate(HttpService *service, HttpRequest *request, AuthRespo
} else if (authDataFound){
ACEE *acee = NULL;
strupcase(request->username); /* upfold username */
if (request->password == NULL) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the password field to indicate whether this is a passwordless auth seems like a bad idea. If for some unexpected reason that field is NULL (is it NULL if a user just doesn't provide a password in the basic auth?), you'll assume this is just a passwordless auth and will use zisCheckUsername, which might say everything is okay.

This seems like an error prone solution with implicit logic.

Regardless of whether this approach with client certificates is correct in the first place, using a separate variable to explicitly indicate what needs to be checked to authenticate would probably be better.

@JoeNemo
Copy link
Contributor

JoeNemo commented Apr 19, 2023

@jordanfilteau1995 , can we discuss a little more. We probaby need to refactor for clarity because the different authentication methods are a little to close in the code, and could share variables and state in unexpected ways. We also may need early help in testing multiple auth methods on a branch before merging.

Copy link
Contributor

@JoeNemo JoeNemo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

Comment on lines +2687 to +2692
} else {
pwdCheckRC = zisCheckUsername(privilegedServerName,
request->username, &status);
authResponse->type = AUTH_TYPE_RACF;
authResponse->responseDetails.safStatus = status.safStatus;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irek, we need either a new API, or a new arg in the existing API to say if password is required.

c/httpserver.c Outdated
}
}

/* Doubtful that it would be greater than 8k... */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the R_usermap doc for limits. Some 'net searching yielded 8K, blame me for this.

@JoeNemo JoeNemo merged commit 18cd519 into v2.x/staging Aug 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants