-
Notifications
You must be signed in to change notification settings - Fork 30
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
Conversation
Signed-off-by: Jordan Filteau <[email protected]>
Signed-off-by: Jordan Filteau <[email protected]>
Signed-off-by: Jordan Filteau <[email protected]>
Signed-off-by: Jordan Filteau <[email protected]>
@@ -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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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++) { |
There was a problem hiding this comment.
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];
. . .
}
@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? |
There was a problem hiding this 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) { |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dead code?
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 */ | ||
} |
There was a problem hiding this comment.
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?
} else { | ||
pwdCheckRC = zisCheckUsername(privilegedServerName, | ||
request->username, &status); | ||
authResponse->type = AUTH_TYPE_RACF; | ||
authResponse->responseDetails.safStatus = status.safStatus; | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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... */ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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.
@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. |
…ls.c; simplying logic for loop in tls.c Signed-off-by: Jordan Filteau <[email protected]>
Signed-off-by: Jordan Filteau <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved
} else { | ||
pwdCheckRC = zisCheckUsername(privilegedServerName, | ||
request->username, &status); | ||
authResponse->type = AUTH_TYPE_RACF; | ||
authResponse->responseDetails.safStatus = status.safStatus; | ||
} |
There was a problem hiding this comment.
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... */ |
There was a problem hiding this comment.
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.
Client certificate is grabbed from gsk after connection is established.