diff --git a/c/httpserver.c b/c/httpserver.c index f88962e18..729988432 100644 --- a/c/httpserver.c +++ b/c/httpserver.c @@ -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->flags & HTTP_REQUEST_NO_PASSWORD)) { + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, "Password is null. Calling safAuthenticate without a password.\n"); + } else { #ifdef ENABLE_DANGEROUS_AUTH_TRACING #ifdef METTLE - printf("SAF auth for user: '%s'\n", request->username); + 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 */ + } } #if APF_AUTHORIZED @@ -2675,10 +2679,17 @@ static int safAuthenticate(HttpService *service, HttpRequest *request, AuthRespo CrossMemoryServerName *privilegedServerName = getConfiguredProperty(service->server, HTTP_SERVER_PRIVILEGED_SERVER_PROPERTY); int pwdCheckRC = 0, pwdCheckRSN = 0; - pwdCheckRC = zisCheckUsernameAndPassword(privilegedServerName, - request->username, request->password, &status); - authResponse->type = AUTH_TYPE_RACF; - authResponse->responseDetails.safStatus = status.safStatus; + if (!(request->flags & HTTP_REQUEST_NO_PASSWORD)) { + pwdCheckRC = zisCheckUsernameAndPassword(privilegedServerName, + request->username, request->password, &status); + authResponse->type = AUTH_TYPE_RACF; + authResponse->responseDetails.safStatus = status.safStatus; + } else { + pwdCheckRC = zisCheckUsername(privilegedServerName, + request->username, &status); + authResponse->type = AUTH_TYPE_RACF; + authResponse->responseDetails.safStatus = status.safStatus; + } if (pwdCheckRC != 0) { #ifdef DEBUG_AUTH @@ -3142,7 +3153,7 @@ static int serviceAuthNativeWithSessionToken(HttpService *service, HttpRequest * int authDataFound = FALSE; HttpHeader *authenticationHeader = getHeader(request,"Authorization"); char *tokenCookieText = getCookieValue(request,getSessionTokenCookieName(service)); - + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG3, "serviceAuthNativeWithSessionToken: authenticationHeader 0x%p\n", "extractFunction 0x%p\n", @@ -3162,9 +3173,54 @@ static int serviceAuthNativeWithSessionToken(HttpService *service, HttpRequest * if (service->authExtractionFunction(service, request) == 0){ authDataFound = TRUE; } + } + } + +#define TLS_CLIENT_CERTIFICATE_MAX_LENGTH 65536 + + char *clientCertificate = safeMalloc(TLS_CLIENT_CERTIFICATE_MAX_LENGTH, "Client Certificate"); + unsigned int clientCertificateLength = 0; + + int rc = getClientCertificate(response->socket->tlsSocket->socketHandle, clientCertificate, TLS_CLIENT_CERTIFICATE_MAX_LENGTH, &clientCertificateLength); + if (rc != 0) { + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG, "getClientCertificate - %d.\n", rc); + } + +#ifdef ENABLE_DANGEROUS_AUTH_TRACING + /* We probably don't want to dump their certificate, right? */ + dumpbuffer(clientCertificate, clientCertificateLength); +#endif + + if (rc == 0 && clientCertificateLength > 0) { + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG, "There is a client certificate attached to the request.\n"); + /* + * We don't want to do this if we already found authentication data. + */ + if (authDataFound == FALSE) { +#define TLS_USERID_LENGTH 9 + char userid[TLS_USERID_LENGTH] = {0}; + int racfReturnCode = 0, racfReasonCode = 0; + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG, "There was no token or credentials found in the request. Server is attempting to map the client certificate.\n"); + int safReturnCode = getUseridByCertificate(clientCertificate, clientCertificateLength, userid, &racfReturnCode, &racfReasonCode); + if (safReturnCode == 0) { + request->username = userid; + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_DEBUG, "Found user '%s' from client certificate.\n", request->username); + request->password = NULL; + request->flags = HTTP_REQUEST_NO_PASSWORD; + authDataFound = TRUE; + } else { + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_INFO, "No user was found for client certificate. (rc = 0x%x racfRC = 0x%x racfRSN = 0x%x\n", safReturnCode, racfReturnCode, racfReasonCode); + } + } else { + zowelog(NULL, LOG_COMP_HTTPSERVER, ZOWE_LOG_INFO, "Client certificate was attached to request, but credentials are also attached. Server won't attempt to map the client certificate.\n"); } } - + + if (clientCertificate) { + safeFree(clientCertificate, TLS_CLIENT_CERTIFICATE_MAX_LENGTH); + clientCertificate = NULL; + } + response->sessionCookie = NULL; AUTH_TRACE("AUTH: tokenCookieText: %s\n",(tokenCookieText ? tokenCookieText : "")); diff --git a/c/tls.c b/c/tls.c index 44a98aec3..2264d2da2 100644 --- a/c/tls.c +++ b/c/tls.c @@ -15,6 +15,44 @@ #include "fdpoll.h" #include "tls.h" +int getClientCertificate(gsk_handle soc_handle, char *clientCertificate, unsigned int clientCertificateBufferSize, unsigned int *clientCertificateLength) { + + int rc = 0; + + if (clientCertificate == NULL || clientCertificateBufferSize <= 0) { + return -1; + } + + memset(clientCertificate, 0, clientCertificateBufferSize); + *clientCertificateLength = 0; + + gsk_cert_data_elem *gskCertificateArray = NULL; + int gskCertificateArrayElementCount = 0; + + rc = gsk_attribute_get_cert_info(soc_handle, GSK_PARTNER_CERT_INFO, &gskCertificateArray, &gskCertificateArrayElementCount); + + if (rc != 0) { + return rc; + } + + for (int i = 0; i < gskCertificateArrayElementCount; i++) { + gsk_cert_data_elem *tmp = &gskCertificateArray[i]; + 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; + } else { + rc = -1; /* tls rc are all positive */ + } + break; + } + } + + gsk_free_cert_data(gskCertificateArray, gskCertificateArrayElementCount); + + return rc; +} + int tlsInit(TlsEnvironment **outEnv, TlsSettings *settings) { int rc = 0; TlsEnvironment *env = (TlsEnvironment *)safeMalloc(sizeof(*env), "Tls Environment"); @@ -29,6 +67,11 @@ int tlsInit(TlsEnvironment **outEnv, TlsSettings *settings) { rc = rc || gsk_attribute_set_enum(env->envHandle, GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_OFF); rc = rc || gsk_attribute_set_enum(env->envHandle, GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON); rc = rc || gsk_attribute_set_enum(env->envHandle, GSK_SERVER_EPHEMERAL_DH_GROUP_SIZE, GSK_SERVER_EPHEMERAL_DH_GROUP_SIZE_2048); + +#ifdef DEV_DO_NOT_VALIDATE_CLIENT_CERTIFICATES + rc = rc || gsk_attribute_set_enum(env->envHandle, GSK_CLIENT_AUTH_TYPE, GSK_CLIENT_AUTH_PASSTHRU_TYPE); +#endif + rc = rc || gsk_attribute_set_buffer(env->envHandle, GSK_KEYRING_FILE, settings->keyring, 0); if (settings->stash) { rc = rc || gsk_attribute_set_buffer(env->envHandle, GSK_KEYRING_STASH_FILE, settings->stash, 0); @@ -94,9 +137,9 @@ static int secureSocketSend(int fd, void *data, int len, char *userData) { } return rc; } - + int tlsSocketInit(TlsEnvironment *env, TlsSocket **outSocket, int fd, bool isServer) { - int rc = 0; + int rc = 0; gsk_iocallback ioCallbacks = {secureSocketRecv, secureSocketSend, NULL, NULL, NULL, NULL}; TlsSocket *socket = (TlsSocket*)safeMalloc(sizeof(TlsSocket), "Tls Socket"); if (!socket) { @@ -109,8 +152,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); if (ciphers) { rc = rc || gsk_attribute_set_buffer(socket->socketHandle, GSK_V3_CIPHER_SPECS_EXPANDED, ciphers, 0); rc = rc || gsk_attribute_set_enum(socket->socketHandle, GSK_V3_CIPHERS, GSK_V3_CIPHERS_CHAR4); diff --git a/h/http.h b/h/http.h index b46114ab3..f7462c7c6 100644 --- a/h/http.h +++ b/h/http.h @@ -126,6 +126,7 @@ typedef struct HttpRequest_tag{ Socket *socket; BufferedInputStream *input; int flags; +#define HTTP_REQUEST_NO_PASSWORD 0x01 int characterEncoding; int contentLength; /* -1 if unknown */ char *contentType; diff --git a/h/tls.h b/h/tls.h index 47ec2935d..f1f9bd59f 100644 --- a/h/tls.h +++ b/h/tls.h @@ -140,6 +140,7 @@ int tlsSocketClose(TlsSocket *socket); int tlsRead(TlsSocket *socket, const char *buf, int size, int *outLength); int tlsWrite(TlsSocket *socket, const char *buf, int size, int *outLength); const char *tlsStrError(int rc); +int getClientCertificate(gsk_handle soc_handle, char *clientCertificate, unsigned int clientCertificateBufferSize, unsigned int *clientCertificateLength); #define TLS_ALLOC_ERROR (-1)