OM_uint32 gss_wrap ( OM_uint32 *minor_status, gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer) { *minor_status = 0; SecPkgContext_Sizes sizes={0}; BOOL b = QueryContextAttributes(&context_handle,SECPKG_ATTR_SIZES,&sizes); char *buffer = (char*)malloc(sizes.cbSecurityTrailer+input_message_buffer->length+sizes.cbBlockSize); SecBuffer InputBuffer[3] = { { sizes.cbSecurityTrailer,SECBUFFER_TOKEN,buffer }, { input_message_buffer->length,SECBUFFER_DATA,buffer+sizes.cbSecurityTrailer }, { sizes.cbBlockSize,SECBUFFER_PADDING,buffer+sizes.cbSecurityTrailer+input_message_buffer->length } }; SecBufferDesc InputBufferDesc = {SECBUFFER_VERSION, 3, InputBuffer}; OM_uint32 ret; memcpy(InputBuffer[1].pvBuffer,input_message_buffer->value,input_message_buffer->length); ret = EncryptMessage(&context_handle, conf_req_flag? 0:KERB_WRAP_NO_ENCRYPT, &InputBufferDesc, 0); output_message_buffer->value=buffer; memmove(buffer+InputBuffer[0].cbBuffer,InputBuffer[1].pvBuffer,InputBuffer[1].cbBuffer); memmove(buffer+InputBuffer[0].cbBuffer+InputBuffer[1].cbBuffer,InputBuffer[2].pvBuffer,InputBuffer[2].cbBuffer); output_message_buffer->length=InputBuffer[0].cbBuffer+InputBuffer[1].cbBuffer+InputBuffer[2].cbBuffer; return ret; }
/* {{{ ma_tls_get_protocol_version(MARIADB_TLS *ctls, struct st_ssl_version *version) */ my_bool ma_tls_get_protocol_version(MARIADB_TLS *ctls, struct st_ssl_version *version) { SC_CTX *sctx; SecPkgContext_ConnectionInfo ConnectionInfo; if (!ctls->ssl) return 1; sctx= (SC_CTX *)ctls->ssl; if (QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_CONNECTION_INFO, &ConnectionInfo) != SEC_E_OK) return 1; switch(ConnectionInfo.dwProtocol) { case SP_PROT_SSL3_CLIENT: version->iversion= 1; break; case SP_PROT_TLS1_CLIENT: version->iversion= 2; break; case SP_PROT_TLS1_1_CLIENT: version->iversion= 3; break; case SP_PROT_TLS1_2_CLIENT: version->iversion= 4; break; default: version->iversion= 0; break; } version->cversion= ssl_protocol_version[version->iversion]; return 0; }
static int tls_write(URLContext *h, const uint8_t *buf, int len) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SECURITY_STATUS sspi_ret; int ret = 0, data_size; uint8_t *data = NULL; SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; if (c->sizes.cbMaximumMessage == 0) { sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes); if (sspi_ret != SEC_E_OK) return AVERROR_UNKNOWN; } /* limit how much data we can consume */ len = FFMIN(len, c->sizes.cbMaximumMessage); data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer; data = av_malloc(data_size); if (data == NULL) return AVERROR(ENOMEM); init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER, data, c->sizes.cbHeader); init_sec_buffer(&outbuf[1], SECBUFFER_DATA, data + c->sizes.cbHeader, len); init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER, data + c->sizes.cbHeader + len, c->sizes.cbTrailer); init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, outbuf, 4); memcpy(outbuf[1].pvBuffer, buf, len); sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0); if (sspi_ret == SEC_E_OK) { len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; ret = ffurl_write(s->tcp, data, len); if (ret < 0 || ret != len) { ret = AVERROR(EIO); av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n"); goto done; } } else { av_log(h, AV_LOG_ERROR, "Encrypting data failed\n"); if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY) ret = AVERROR(ENOMEM); else ret = AVERROR(EIO); goto done; } done: av_freep(&data); return ret < 0 ? ret : outbuf[1].cbBuffer; }
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags) { SECURITY_STATUS sRet; DWORD flags; MARIADB_PVIO *pvio= sctx->mysql->net.pvio; PCCERT_CONTEXT pServerCert= NULL; if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); return 0; } flags= CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG; if (sctx->client_ca_ctx) { if (!(sRet= CertVerifySubjectCertificateContext(pServerCert, sctx->client_ca_ctx, &flags))) { ma_schannel_set_win_error(pvio); return 0; } if (flags) { if ((flags & CERT_STORE_SIGNATURE_FLAG) != 0) pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Certificate signature check failed"); else if ((flags & CERT_STORE_REVOCATION_FLAG) != 0) pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "certificate was revoked"); else if ((flags & CERT_STORE_TIME_VALIDITY_FLAG) != 0) pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "certificate has expired"); else pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown error during certificate validation"); return 0; } } /* Check if none of the certificates in the certificate chain have been revoked. */ if (sctx->client_crl_ctx) { PCRL_INFO Info[1]; Info[0]= sctx->client_crl_ctx->pCrlInfo; if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pServerCert->pCertInfo, 1, Info)) ) { pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed"); return 0; } } return 1; }
unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, unsigned char *fp, unsigned int len) { SC_CTX *sctx= (SC_CTX *)ctls->ssl; PCCERT_CONTEXT pRemoteCertContext = NULL; if (QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK) return 0; CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len); return len; }
OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle, int conf_req_flag,gss_qop_t qop_req, gss_buffer_t input_message_buffer,int *conf_state, gss_buffer_t output_message_buffer) { OM_uint32 major_status; SecBuffer buf[3]; SecBufferDesc bufs; SecPkgContext_Sizes sizes; *minor_status = NIL; /* never any minor status */ *conf_state = conf_req_flag; /* same as requested */ if ((major_status = /* get trailer and padding sizes */ QueryContextAttributes (context_handle,SECPKG_ATTR_SIZES,&sizes)) == SEC_E_OK) { /* create big enough output buffer */ output_message_buffer->value = fs_get (sizes.cbSecurityTrailer + input_message_buffer->length + sizes.cbBlockSize); /* MSDN claims that for EncryptMessage() in Kerberos, you need an * uninitialized SECBUFFER_STREAM_HEADER; a SECBUFFER_DATA that "contains * the message to be encrypted. The message is encrypted in place, * overwirting the original contents of its buffer"; an uninitialized * SECBUFFER_STREAM_TRAILER, and an uninitialized SECBUFFER_EMPTY. I've * never been able to get it to work that way. */ bufs.cBuffers = 3; /* set up buffer descriptor */ bufs.pBuffers = buf; bufs.ulVersion = SECBUFFER_VERSION; buf[0].BufferType = SECBUFFER_TOKEN; buf[0].pvBuffer = output_message_buffer->value; buf[0].cbBuffer = sizes.cbSecurityTrailer; /* I/O buffer */ buf[1].BufferType = SECBUFFER_DATA; buf[1].pvBuffer = ((char *) buf[0].pvBuffer) + buf[0].cbBuffer; buf[1].cbBuffer = input_message_buffer->length; memcpy (buf[1].pvBuffer,input_message_buffer->value,buf[1].cbBuffer); buf[2].BufferType = SECBUFFER_PADDING; buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer; buf[2].cbBuffer = sizes.cbBlockSize; if ((major_status = EncryptMessage (context_handle,qop_req,&bufs,0)) == GSS_S_COMPLETE) { /* slide data as necessary (how annoying!) */ unsigned long i = sizes.cbSecurityTrailer - buf[0].cbBuffer; if (i) buf[1].pvBuffer = memmove (((char *) buf[0].pvBuffer) + buf[0].cbBuffer, buf[1].pvBuffer,buf[1].cbBuffer); if (i += (input_message_buffer->length - buf[1].cbBuffer)) buf[1].pvBuffer = memmove (((char *)buf[1].pvBuffer) + buf[1].cbBuffer, buf[2].pvBuffer,buf[2].cbBuffer); output_message_buffer->length = buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer; } else fs_give (&output_message_buffer->value); } return major_status; /* return status */ }
SECURITY_STATUS SSL_SOCKET :: VerifySessionCertificate() { PCCERT_CONTEXT pRemoteCertContext = NULL; SECURITY_STATUS Status = QueryContextAttributes(&hCtx,SECPKG_ATTR_REMOTE_CERT_CONTEXT,(PVOID)&pRemoteCertContext); if (Status != SEC_E_OK) return Status; Status = Verify(pRemoteCertContext); CertFreeCertificateContext(pRemoteCertContext); return Status; }
/* sqExtractPeerName: Extract the name from the cert of the remote peer. */ static int sqExtractPeerName(sqSSL *ssl) { SECURITY_STATUS ret; PCCERT_CONTEXT certHandle = NULL; PCERT_NAME_INFO certInfo = NULL; PCERT_RDN_ATTR certAttr = NULL; DWORD dwSize = 0; char tmpBuf[1024]; if(ssl->peerName) { free(ssl->peerName); ssl->peerName = NULL; } ret = QueryContextAttributes(&ssl->sslCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&certHandle); /* No credentials were provided; can't extract peer name */ if(ret == SEC_E_NO_CREDENTIALS) return 1; if(ret != SEC_E_OK) { if(ssl->loglevel) printf("sqExtractPeerName: QueryContextAttributes failed (code = %x)\n", ret); return 0; } /* Figure out the size of the blob */ if(!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_NAME, certHandle->pCertInfo->Subject.pbData, certHandle->pCertInfo->Subject.cbData, 0, NULL, &dwSize)) { if(ssl->loglevel) printf("sqExtractPeerName: CryptDecodeObject failed\n"); return 0; } /* Get the contents */ certInfo = alloca(dwSize); if(!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_NAME, certHandle->pCertInfo->Subject.pbData, certHandle->pCertInfo->Subject.cbData, 0, certInfo, &dwSize)) { if(ssl->loglevel) printf("sqExtractPeerName: CryptDecodeObject failed\n"); return 0; } /* Fetch the CN from the cert */ certAttr = CertFindRDNAttr(szOID_COMMON_NAME, certInfo); if(certAttr == NULL) return 0; /* Translate from RDN to string */ if(CertRDNValueToStr(CERT_RDN_PRINTABLE_STRING, &certAttr->Value, tmpBuf, sizeof(tmpBuf)) == 0) return 0; ssl->peerName = _strdup(tmpBuf); if(ssl->loglevel) printf("sqExtractPeerName: Peer name is %s\n", ssl->peerName); CertFreeCertificateContext(certHandle); return 1; }
Certificate::ref SchannelContext::getPeerCertificate() const { SchannelCertificate::ref pCertificate; ScopedCertContext pServerCert; SECURITY_STATUS status = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset()); if (status != SEC_E_OK) return pCertificate; pCertificate.reset( new SchannelCertificate(pServerCert) ); return pCertificate; }
void SSL_SOCKET :: GetCertificateInfoString(TCHAR* s) { PCCERT_CONTEXT pRemoteCertContext = NULL; SECURITY_STATUS Status = QueryContextAttributes(&hCtx,SECPKG_ATTR_REMOTE_CERT_CONTEXT,(PVOID)&pRemoteCertContext); if (Status != SEC_E_OK) return; CertGetNameString( pRemoteCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, s, 1000); CertFreeCertificateContext(pRemoteCertContext); }
AUTH_RESULT GSSAPISession::authenticate() { #ifdef Q_OS_WIN SECURITY_STATUS status; _inSecBuf.cbBuffer = static_cast<unsigned long>(inBuffer.length()); _inSecBuf.BufferType = SECBUFFER_TOKEN; _inSecBuf.pvBuffer = inBuffer.data(); _outSecBuf.cbBuffer = _info->cbMaxToken; CtxtHandle* contextPtr = &_context; if(_first) { contextPtr = NULL; _first = false; } status = AcceptSecurityContext ( &_serverHandle, contextPtr, &_inSecBufDesc, 0, SECURITY_NATIVE_DREP, &_context, &_outSecBufDesc, &_attrs, &_serviceLifetime ); outBuffer = QByteArray((const char *)_outSecBuf.pvBuffer, _outSecBuf.cbBuffer); if(status == SEC_I_CONTINUE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) return AUTH_RESULT::CONTINUE; if(status == 0) { status = QuerySecurityContextToken(&_context, &_secToken); status = QueryContextAttributes(&_context, SECPKG_ATTR_NAMES, &_names); return AUTH_RESULT::ACCEPTED; } return AUTH_RESULT::REJECTED; #endif #ifdef Q_OS_LINUX throw "not implemented"; return AUTH_RESULT::REJECTED; #endif }
void RPC_ENTRY kull_m_rpc_drsr_RpcSecurityCallback(void *Context) { RPC_STATUS rpcStatus; SECURITY_STATUS secStatus; PCtxtHandle data = NULL; rpcStatus = I_RpcBindingInqSecurityContext(Context, (LPVOID *) &data); if(rpcStatus == RPC_S_OK) { if(kull_m_rpc_drsr_g_sKey.SessionKey) { FreeContextBuffer(kull_m_rpc_drsr_g_sKey.SessionKey); kull_m_rpc_drsr_g_sKey.SessionKeyLength = 0; kull_m_rpc_drsr_g_sKey.SessionKey = NULL; } secStatus = QueryContextAttributes(data, SECPKG_ATTR_SESSION_KEY, (LPVOID) &kull_m_rpc_drsr_g_sKey); if(secStatus != SEC_E_OK) PRINT_ERROR(L"QueryContextAttributes %08x\n", secStatus); } else PRINT_ERROR(L"I_RpcBindingInqSecurityContext %08x\n", rpcStatus); }
OM_uint32 gss_unwrap ( OM_uint32 * minor_status, gss_ctx_id_t context_handle, gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, gss_qop_t * qop_state) { SecPkgContext_Sizes sizes={0}; BOOL b = QueryContextAttributes(&context_handle,SECPKG_ATTR_SIZES,&sizes); SecBuffer InputBuffer[2] = { { input_message_buffer->length,SECBUFFER_STREAM,input_message_buffer->value }, { 0,SECBUFFER_DATA,NULL }, }; SecBufferDesc InputBufferDesc = {SECBUFFER_VERSION, 2, InputBuffer}; OM_uint32 ret; ret = DecryptMessage(&context_handle, &InputBufferDesc, 0, (unsigned long*)qop_state); output_message_buffer->value=InputBuffer[1].pvBuffer; output_message_buffer->length=InputBuffer[1].cbBuffer; *minor_status = 0; return ret; }
const char *ma_tls_get_cipher(MARIADB_TLS *ctls) { SecPkgContext_ConnectionInfo cinfo; SECURITY_STATUS sRet; SC_CTX *sctx; DWORD i= 0; if (!ctls || !ctls->ssl) return NULL; sctx= (SC_CTX *)ctls->ssl; sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_CONNECTION_INFO, (PVOID)&cinfo); if (sRet != SEC_E_OK) return NULL; while (valid_ciphers[i].cipher) { if (valid_ciphers[i].aid == cinfo.aiCipher) return valid_ciphers[i].cipher; i++; } return NULL; }
int sserver_connect(const struct protocol_interface *protocol, int verify_only) { char crypt_password[64]; char server_version[128]; char tmp_keyname[256]; const char *begin_request = "BEGIN SSL AUTH REQUEST"; const char *end_request = "END SSL AUTH REQUEST"; const char *username = NULL; const char *cert = current_server()->current_root->optional_3; int l; int sserver_version = 0; int strict = 0; CScramble scramble; bool send_client_version = false; if(current_server()->current_root->optional_1) { sserver_version = atoi(current_server()->current_root->optional_1); if(sserver_version != 0 && sserver_version != 1) { server_error(0,"version must be one of:"); server_error(0,"0 - All CVSNT-type servers"); server_error(0,"1 - Unix server using Corey Minards' sserver patches"); server_error(1,"Please specify a valid value"); } } if(!CGlobalSettings::GetUserValue("cvsnt","sserver","StrictChecking",server_version,sizeof(server_version))) { strict = atoi(server_version); } if(!cert && !CGlobalSettings::GetUserValue("cvsnt","sserver","ClientCert",tmp_keyname,sizeof(tmp_keyname))) { cert = tmp_keyname; } if(current_server()->current_root->optional_2) strict = atoi(current_server()->current_root->optional_2); if(sserver_version == 1) /* Old sserver */ { begin_request = verify_only?"BEGIN SSL VERIFICATION REQUEST":"BEGIN SSL REQUEST"; end_request = verify_only?"END SSL VERIFICATION REQUEST":"END SSL REQUEST"; } else if(verify_only) { begin_request = "BEGIN SSL VERIFICATION REQUEST"; end_request = "END SSL VERIFICATION REQUEST"; } username = get_username(current_server()->current_root); if(!username || !current_server()->current_root->hostname || !current_server()->current_root->directory) return CVSPROTO_BADPARMS; if(tcp_connect(current_server()->current_root)) return CVSPROTO_FAIL; if(current_server()->current_root->password) strncpy(crypt_password,scramble.Scramble(current_server()->current_root->password),sizeof(crypt_password)); else { if(sserver_get_user_password(username,current_server()->current_root->hostname,current_server()->current_root->port,current_server()->current_root->directory,crypt_password,sizeof(crypt_password))) { /* Using null password - trace something out here */ server_error(0,"Using an empty password; you may need to do 'cvs login' with a real password\n"); strncpy(crypt_password,scramble.Scramble(""),sizeof(crypt_password)); } } if(sserver_version == 0) /* Pre-CVSNT had no version check */ { if(tcp_printf("%s\n",begin_request)<0) return CVSPROTO_FAIL; for(;;) { *server_version='\0'; if((l=tcp_readline(server_version,sizeof(server_version))<0)) return CVSPROTO_FAIL; if(*server_version) break; #ifdef _WIN32 Sleep(10); #else usleep(10); #endif } if(strncmp(server_version,"SSERVER ",8)) { server_error(0,"%s\n",server_version); return CVSPROTO_FAIL; } if(strncmp(server_version+8,"1.0 ",4)) send_client_version = true; } if(!ClientAuthenticate(cert,current_server()->current_root->hostname)) return CVSPROTO_AUTHFAIL; QueryContextAttributes(&contextHandle,SECPKG_ATTR_STREAM_SIZES,&secSizes); PCERT_CONTEXT sc; PCCERT_CHAIN_CONTEXT pcc; CERT_SIMPLE_CHAIN *psc; CERT_CHAIN_PARA para = { sizeof(CERT_CHAIN_PARA) }; DWORD trust,rc; rc = QueryContextAttributes(&contextHandle,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&sc); if(rc) server_error(1,"Couldn't get server certificate"); if(!CertGetCertificateChain(NULL, sc, NULL, NULL, ¶, 0, NULL, &pcc)) server_error(1,"Couldn't get server certificate chain"); psc = pcc->rgpChain[0]; trust = psc->TrustStatus.dwErrorStatus; if (trust) { if (trust & (CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_IS_UNTRUSTED_ROOT)) ; // Seld signed else if (trust & (CERT_TRUST_IS_NOT_TIME_VALID)) server_error(1,"Server certificate expired"); else server_error(1,"Server certificate verification failed - %08x",trust); } if(strict) { char certname[256]; CertGetNameString(sc, CERT_NAME_DNS_TYPE, 0, NULL, certname, sizeof(certname)); if(strcasecmp(certname,current_server()->current_root->hostname)) server_error(1, "Certificate CommonName '%s' does not match server name '%s'\n",certname,current_server()->current_root->hostname); } CertFreeCertificateChain(pcc); FreeContextBuffer(sc); g_sslBufferInPos=g_sslBufferOutPos=0; g_sslBufferInLen=g_sslBufferOutLen=0; if(sserver_version == 1) { if(sserver_printf("%s\n",begin_request)<0) return CVSPROTO_FAIL; } // For server versions 1.1+ send CLIENT_VERSION_STRING if(send_client_version && sserver_printf(SSERVER_CLIENT_VERSION_STRING)<0) return CVSPROTO_FAIL; if(sserver_printf("%s\n%s\n",current_server()->current_root->directory,username)<0) return CVSPROTO_FAIL; if(sserver_printf("%s\n",crypt_password)<0) return CVSPROTO_FAIL; if(sserver_printf("%s\n",end_request)<0) return CVSPROTO_FAIL; return CVSPROTO_SUCCESS; }
int _mongoc_sspi_auth_sspi_client_wrap (mongoc_sspi_client_state_t *state, SEC_CHAR *data, SEC_CHAR *user, ULONG ulen, int protect) { SECURITY_STATUS status; SecPkgContext_Sizes sizes; SecBuffer wrapBufs[3]; SecBufferDesc wrapBufDesc; SEC_CHAR *decodedData = NULL; SEC_CHAR *inbuf; SIZE_T inbufSize; SEC_CHAR *outbuf; DWORD outbufSize; SEC_CHAR *plaintextMessage; ULONG plaintextMessageSize; if (state->response != NULL) { free (state->response); state->response = NULL; } if (!state->haveCtx) { return MONGOC_SSPI_AUTH_GSS_ERROR; } status = QueryContextAttributes (&state->ctx, SECPKG_ATTR_SIZES, &sizes); if (status != SEC_E_OK) { _mongoc_sspi_set_gsserror (status, "QueryContextAttributes"); return MONGOC_SSPI_AUTH_GSS_ERROR; } if (user) { /* Length of user + 4 bytes for security layer (see below). */ plaintextMessageSize = ulen + 4; } else { decodedData = _mongoc_sspi_base64_decode (data, &plaintextMessageSize); if (!decodedData) { return MONGOC_SSPI_AUTH_GSS_ERROR; } } inbufSize = sizes.cbSecurityTrailer + plaintextMessageSize + sizes.cbBlockSize; inbuf = (SEC_CHAR *) malloc (inbufSize); if (inbuf == NULL) { free (decodedData); return MONGOC_SSPI_AUTH_GSS_ERROR; } plaintextMessage = inbuf + sizes.cbSecurityTrailer; if (user) { /* Authenticate the provided user. Unlike pykerberos, we don't * need any information from "data" to do that. * */ plaintextMessage[0] = 1; /* No security layer */ plaintextMessage[1] = 0; plaintextMessage[2] = 0; plaintextMessage[3] = 0; memcpy_s (plaintextMessage + 4, inbufSize - sizes.cbSecurityTrailer - 4, user, strlen (user)); } else { /* No user provided. Just rewrap data. */ memcpy_s (plaintextMessage, inbufSize - sizes.cbSecurityTrailer, decodedData, plaintextMessageSize); free (decodedData); } wrapBufDesc.cBuffers = 3; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer; wrapBufs[0].BufferType = SECBUFFER_TOKEN; wrapBufs[0].pvBuffer = inbuf; wrapBufs[1].cbBuffer = (ULONG) plaintextMessageSize; wrapBufs[1].BufferType = SECBUFFER_DATA; wrapBufs[1].pvBuffer = inbuf + sizes.cbSecurityTrailer; wrapBufs[2].cbBuffer = sizes.cbBlockSize; wrapBufs[2].BufferType = SECBUFFER_PADDING; wrapBufs[2].pvBuffer = inbuf + (sizes.cbSecurityTrailer + plaintextMessageSize); status = EncryptMessage ( &state->ctx, protect ? 0 : SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0); if (status != SEC_E_OK) { free (inbuf); _mongoc_sspi_set_gsserror (status, "EncryptMessage"); return MONGOC_SSPI_AUTH_GSS_ERROR; } outbufSize = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; outbuf = (SEC_CHAR *) malloc (sizeof (SEC_CHAR) * outbufSize); memcpy_s (outbuf, outbufSize, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy_s (outbuf + wrapBufs[0].cbBuffer, outbufSize - wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); memcpy_s (outbuf + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, outbufSize - wrapBufs[0].cbBuffer - wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer); state->response = _mongoc_sspi_base64_encode (outbuf, outbufSize); if (!state->response) { status = MONGOC_SSPI_AUTH_GSS_ERROR; } else { status = MONGOC_SSPI_AUTH_GSS_COMPLETE; } free (inbuf); free (outbuf); return status; }
int sspiSendClientAuthzId(SspiConnContext* pcctx, sasl_client_params_t* cparams, const char *serverin, unsigned serverinlen, const char **clientout, unsigned *clientoutlen, sasl_out_params_t* oparams) { // Ensure server response is decryptable. int decryptStatus = sspiValidateServerSecurityLayerOffering(pcctx, cparams, serverin, serverinlen); if (decryptStatus != SASL_OK) { return decryptStatus; } // Fill in AUTHID and AUTHZID fields in oparams. int ret = cparams->canon_user(cparams->utils->conn, pcctx->userPlusRealm.c_str(), 0, SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); // Reply to server with security capability and authz name. SecPkgContext_Sizes sizes; SECURITY_STATUS status = QueryContextAttributes(&pcctx->ctx, SECPKG_ATTR_SIZES, &sizes); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "QueryContextAttributes(sizes)"); return SASL_FAIL; } // See RFC4752. int plaintextMessageSize = 4 + pcctx->userPlusRealm.size(); boost::scoped_array<char> message(new char[sizes.cbSecurityTrailer + plaintextMessageSize + sizes.cbBlockSize]); char* plaintextMessage = message.get() + sizes.cbSecurityTrailer; plaintextMessage[0] = 1; // LAYER_NONE plaintextMessage[1] = 0; plaintextMessage[2] = 0; plaintextMessage[3] = 0; memcpy(&plaintextMessage[4], pcctx->userPlusRealm.c_str(), pcctx->userPlusRealm.size()); SecBuffer wrapBufs[3]; SecBufferDesc wrapBufDesc; wrapBufDesc.cBuffers = 3; wrapBufDesc.pBuffers = wrapBufs; wrapBufDesc.ulVersion = SECBUFFER_VERSION; wrapBufs[0].cbBuffer = sizes.cbSecurityTrailer; wrapBufs[0].BufferType = SECBUFFER_TOKEN; wrapBufs[0].pvBuffer = message.get(); wrapBufs[1].cbBuffer = plaintextMessageSize; wrapBufs[1].BufferType = SECBUFFER_DATA; wrapBufs[1].pvBuffer = message.get() + sizes.cbSecurityTrailer; wrapBufs[2].cbBuffer = sizes.cbBlockSize; wrapBufs[2].BufferType = SECBUFFER_PADDING; wrapBufs[2].pvBuffer = message.get() + sizes.cbSecurityTrailer + plaintextMessageSize; status = EncryptMessage(&pcctx->ctx, SECQOP_WRAP_NO_ENCRYPT, &wrapBufDesc, 0); if (status != SEC_E_OK) { HandleLastError(cparams->utils, status, "EncryptMessage"); return SASL_FAIL; } // Create the message to send to server. *clientoutlen = wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer + wrapBufs[2].cbBuffer; char *newoutbuf = static_cast<char*>(cparams->utils->malloc(*clientoutlen)); memcpy(newoutbuf, wrapBufs[0].pvBuffer, wrapBufs[0].cbBuffer); memcpy(newoutbuf + wrapBufs[0].cbBuffer, wrapBufs[1].pvBuffer, wrapBufs[1].cbBuffer); memcpy(newoutbuf + wrapBufs[0].cbBuffer + wrapBufs[1].cbBuffer, wrapBufs[2].pvBuffer, wrapBufs[2].cbBuffer); *clientout = newoutbuf; return SASL_OK; }
void main() { SOCKET Client_Socket; BYTE Data[BIG_BUFF]; PCHAR pMessage; WSADATA wsaData; CredHandle hCred; struct _SecHandle hCtxt; SECURITY_STATUS ss; DWORD cbRead; ULONG cbMaxSignature; ULONG cbSecurityTrailer; SecPkgContext_Sizes SecPkgContextSizes; SecPkgContext_NegotiationInfo SecPkgNegInfo; BOOL DoAuthentication (SOCKET s); //------------------------------------------------------------------- // Initialize the socket and the SSP security package. if(WSAStartup (0x0101, &wsaData)) { MyHandleError("Could not initialize winsock "); } //-------------------------------------------------------------------- // Connect to a server. if (!ConnectAuthSocket ( &Client_Socket, &hCred, &hCtxt)) { MyHandleError("Authenticated server connection "); } //-------------------------------------------------------------------- // An authenticated session with a server has been established. // Receive and manage a message from the server. // First, find and display the name of the negotiated // SSP and the size of the signature and the encryption // trailer blocks for this SSP. ss = QueryContextAttributes( &hCtxt, SECPKG_ATTR_NEGOTIATION_INFO, &SecPkgNegInfo ); if (!SEC_SUCCESS(ss)) { MyHandleError("QueryContextAttributes failed "); } else { printf("Package Name: %s\n", SecPkgNegInfo.PackageInfo->Name); } ss = QueryContextAttributes( &hCtxt, SECPKG_ATTR_SIZES, &SecPkgContextSizes ); if (!SEC_SUCCESS(ss)) { MyHandleError("Query context "); } cbMaxSignature = SecPkgContextSizes.cbMaxSignature; cbSecurityTrailer = SecPkgContextSizes.cbSecurityTrailer; printf("InitializeSecurityContext result = 0x%08x\n", ss); //-------------------------------------------------------------------- // Decrypt and display the message from the server. if (!ReceiveBytes( Client_Socket, Data, BIG_BUFF, &cbRead)) { MyHandleError("No response from server "); } if (0 == cbRead) { MyHandleError("Zero bytes received "); } pMessage = (PCHAR) DecryptThis( Data, &cbRead, &hCtxt, cbSecurityTrailer); printf ("The message from the server is \n -> %.*s \n", cbRead, pMessage); //-------------------------------------------------------------------- // Terminate socket and security package. DeleteSecurityContext (&hCtxt); FreeCredentialHandle (&hCred); shutdown (Client_Socket, 2); closesocket (Client_Socket); if (SOCKET_ERROR == WSACleanup ()) { MyHandleError("Problem with socket cleanup "); } exit (EXIT_SUCCESS); } // end main
/* * '_sspiAccept()' - Accept an SSL/TLS connection */ BOOL /* O - 1 on success, 0 on failure */ _sspiAccept(_sspi_struct_t *conn) /* I - Client connection */ { DWORD dwSSPIFlags; /* SSL connection attributes we want */ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS scRet; /* SSPI Status */ SecBufferDesc inBuffer; /* Array of SecBuffer structs */ SecBuffer inBuffers[2]; /* Security package buffer */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ DWORD num = 0; /* 32 bit status value */ BOOL fInitContext = TRUE; /* Has the context been init'd? */ BOOL ok = TRUE; /* Return value */ if (!conn) return (FALSE); dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | ASC_REQ_CONFIDENTIALITY | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_STREAM; conn->decryptBufferUsed = 0; /* * Set OutBuffer for AcceptSecurityContext call */ outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; scRet = SEC_I_CONTINUE_NEEDED; while (scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE)) { if (conn->decryptBufferLength <= conn->decryptBufferUsed) { conn->decryptBufferLength += 4096; conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength); if (!conn->decryptBuffer) { DEBUG_printf(("_sspiAccept: unable to allocate %d byte decrypt buffer", conn->decryptBufferLength)); ok = FALSE; goto cleanup; } } for (;;) { num = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed, (int)(conn->decryptBufferLength - conn->decryptBufferUsed), 0); if ((num == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK)) Sleep(1); else break; } if (num == SOCKET_ERROR) { DEBUG_printf(("_sspiAccept: recv failed: %d", WSAGetLastError())); ok = FALSE; goto cleanup; } else if (num == 0) { DEBUG_printf(("_sspiAccept: client disconnected")); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiAccept: received %d (handshake) bytes from client", num)); conn->decryptBufferUsed += num; } /* * InBuffers[1] is for getting extra data that * SSPI/SCHANNEL doesn't proccess on this * run around the loop. */ inBuffers[0].pvBuffer = conn->decryptBuffer; inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; inBuffers[1].cbBuffer = 0; inBuffers[1].BufferType = SECBUFFER_EMPTY; inBuffer.cBuffers = 2; inBuffer.pBuffers = inBuffers; inBuffer.ulVersion = SECBUFFER_VERSION; /* * Initialize these so if we fail, pvBuffer contains NULL, * so we don't try to free random garbage at the quit */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context), &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP, (fInitContext?&conn->context:NULL), &outBuffer, &dwSSPIOutFlags, &tsExpiry); fInitContext = FALSE; if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0))) { if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { /* * Send response to server if there is one */ num = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if ((num == SOCKET_ERROR) || (num == 0)) { DEBUG_printf(("_sspiAccept: handshake send failed: %d", WSAGetLastError())); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiAccept: send %d handshake bytes to client", outBuffers[0].cbBuffer)); FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } } if (scRet == SEC_E_OK) { /* * If there's extra data then save it for * next time we go to decrypt */ if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memcpy(conn->decryptBuffer, (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)), inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; } else { conn->decryptBufferUsed = 0; } ok = TRUE; break; } else if (FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE)) { DEBUG_printf(("_sspiAccept: AcceptSecurityContext failed: %x", scRet)); ok = FALSE; break; } if (scRet != SEC_E_INCOMPLETE_MESSAGE && scRet != SEC_I_INCOMPLETE_CREDENTIALS) { if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memcpy(conn->decryptBuffer, (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)), inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; } else { conn->decryptBufferUsed = 0; } } } if (ok) { conn->contextInitialized = TRUE; /* * Find out how big the header will be: */ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiAccept: QueryContextAttributes failed: %x", scRet)); ok = FALSE; } } cleanup: return (ok); }
/* * '_sspiConnect()' - Make an SSL connection. This function * assumes a TCP/IP connection has already * been successfully made */ BOOL /* O - 1 on success, 0 on failure */ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ const CHAR *hostname) /* I - Server hostname */ { PCCERT_CONTEXT serverCert; /* Server certificate */ DWORD dwSSPIFlags; /* SSL connection attributes we want */ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS scRet; /* Status */ DWORD cbData; /* Data count */ SecBufferDesc inBuffer; /* Array of SecBuffer structs */ SecBuffer inBuffers[2]; /* Security package buffer */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ BOOL ok = TRUE; /* Return value */ serverCert = NULL; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* * Initiate a ClientHello message and generate a token. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry); if (scRet != SEC_I_CONTINUE_NEEDED) { DEBUG_printf(("_sspiConnect: InitializeSecurityContext(1) failed: %x", scRet)); ok = FALSE; goto cleanup; } /* * Send response to server if there is one. */ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if ((cbData == SOCKET_ERROR) || !cbData) { DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&conn->context); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData)); /* * Free output buffer. */ FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; conn->decryptBufferUsed = 0; /* * Loop until the handshake is finished or an error occurs. */ scRet = SEC_I_CONTINUE_NEEDED; while(scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE)) { if (conn->decryptBufferLength <= conn->decryptBufferUsed) { conn->decryptBufferLength += 4096; conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength); if (!conn->decryptBuffer) { DEBUG_printf(("_sspiConnect: unable to allocate %d byte decrypt buffer", conn->decryptBufferLength)); SetLastError(E_OUTOFMEMORY); ok = FALSE; goto cleanup; } } cbData = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed, (int) (conn->decryptBufferLength - conn->decryptBufferUsed), 0); if (cbData == SOCKET_ERROR) { DEBUG_printf(("_sspiConnect: recv failed: %d", WSAGetLastError())); ok = FALSE; goto cleanup; } else if (cbData == 0) { DEBUG_printf(("_sspiConnect: server unexpectedly disconnected")); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiConnect: %d bytes of handshake data received", cbData)); conn->decryptBufferUsed += cbData; } /* * Set up the input buffers. Buffer 0 is used to pass in data * received from the server. Schannel will consume some or all * of this. Leftover data (if any) will be placed in buffer 1 and * given a buffer type of SECBUFFER_EXTRA. */ inBuffers[0].pvBuffer = conn->decryptBuffer; inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; inBuffers[1].cbBuffer = 0; inBuffers[1].BufferType = SECBUFFER_EMPTY; inBuffer.cBuffers = 2; inBuffer.pBuffers = inBuffers; inBuffer.ulVersion = SECBUFFER_VERSION; /* * Set up the output buffers. These are initialized to NULL * so as to make it less likely we'll attempt to free random * garbage later. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType= SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; /* * Call InitializeSecurityContext. */ scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry); /* * If InitializeSecurityContext was successful (or if the error was * one of the special extended ones), send the contends of the output * buffer to the server. */ if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) { if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if ((cbData == SOCKET_ERROR) || !cbData) { DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&conn->context); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData)); /* * Free output buffer. */ FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } } /* * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, * then we need to read more data from the server and try again. */ if (scRet == SEC_E_INCOMPLETE_MESSAGE) continue; /* * If InitializeSecurityContext returned SEC_E_OK, then the * handshake completed successfully. */ if (scRet == SEC_E_OK) { /* * If the "extra" buffer contains data, this is encrypted application * protocol layer stuff. It needs to be saved. The application layer * will later decrypt it with DecryptMessage. */ DEBUG_printf(("_sspiConnect: Handshake was successful")); if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { if (conn->decryptBufferLength < inBuffers[1].cbBuffer) { conn->decryptBuffer = realloc(conn->decryptBuffer, inBuffers[1].cbBuffer); if (!conn->decryptBuffer) { DEBUG_printf(("_sspiConnect: unable to allocate %d bytes for decrypt buffer", inBuffers[1].cbBuffer)); SetLastError(E_OUTOFMEMORY); ok = FALSE; goto cleanup; } } memmove(conn->decryptBuffer, conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; DEBUG_printf(("_sspiConnect: %d bytes of app data was bundled with handshake data", conn->decryptBufferUsed)); } else conn->decryptBufferUsed = 0; /* * Bail out to quit */ break; } /* * Check for fatal error. */ if (FAILED(scRet)) { DEBUG_printf(("_sspiConnect: InitializeSecurityContext(2) failed: %x", scRet)); ok = FALSE; break; } /* * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, * then the server just requested client authentication. */ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) { /* * Unimplemented */ DEBUG_printf(("_sspiConnect: server requested client credentials")); ok = FALSE; break; } /* * Copy any leftover data from the "extra" buffer, and go around * again. */ if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memmove(conn->decryptBuffer, conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; } else { conn->decryptBufferUsed = 0; } } if (ok) { conn->contextInitialized = TRUE; /* * Get the server cert */ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID*) &serverCert ); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet)); ok = FALSE; goto cleanup; } scRet = sspi_verify_certificate(serverCert, hostname, conn->certFlags); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiConnect: sspi_verify_certificate failed: %x", scRet)); ok = FALSE; goto cleanup; } /* * Find out how big the header/trailer will be: */ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet)); ok = FALSE; } } cleanup: if (serverCert) CertFreeCertificateContext(serverCert); return (ok); }
static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; SCHANNEL_CRED tlscred; CERT_CONTEXT *cert; CERT_CHAIN_PARA chparam; CERT_CHAIN_CONTEXT *chain; SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy; CERT_CHAIN_POLICY_PARA polparam; CERT_CHAIN_POLICY_STATUS status; char tmp[MAILTMPLEN],certname[256]; char *reason = NIL; ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | ISC_REQ_MANUAL_CRED_VALIDATION; LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; PWSTR whost = NIL; char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* initialize TLS credential */ memset (&tlscred,0,sizeof (SCHANNEL_CRED)); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ if (AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? &tlscred : NIL,NIL,NIL,&stream->cred,&t) != SEC_E_OK) reason = "Acquire credentials handle failed"; else while (!reason) { /* negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) reason = "Unexpected TCP output disconnect"; /* free the buffer */ FreeContextBuffer (obuf[0].pvBuffer); } if (!reason) switch (e) { /* negotiation state */ case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (!tcp_getdata (stream->tcpstream)) reason = "Unexpected TCP input disconnect"; else { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } break; case SEC_E_OK: /* success, any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (!(flags & NET_NOVALIDATECERT)) { /* need validation, make wchar of host */ if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) && (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) && MultiByteToWideChar (CP_ACP,0,host,-1,whost,size))) fatal ("Can't make wchar of host name!"); /* get certificate */ if ((QueryContextAttributes (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) != SEC_E_OK) || !cert) { reason = "*Unable to get certificate"; strcpy (certname,"<no certificate>"); } else { /* get certificate subject name */ CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->Subject,CERT_X500_NAME_STR, certname,255); /* build certificate chain */ memset (&chparam,0,sizeof (chparam)); chparam.cbSize = sizeof (chparam); chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage; chparam.RequestedUsage.Usage.cUsageIdentifier = sizeof (usage) / sizeof (LPSTR); if (!CertGetCertificateChain (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain)) reason = ssl_analyze_status (GetLastError (),tmp); else { /* validate certificate chain */ memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA)); policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA); policy.dwAuthType = AUTHTYPE_SERVER; policy.fdwChecks = NIL; policy.pwszServerName = whost; memset (&polparam,0,sizeof (polparam)); polparam.cbSize = sizeof (polparam); polparam.pvExtraPolicyPara = &policy; memset (&status,0,sizeof (status)); status.cbSize = sizeof (status); if (!CertVerifyCertificateChainPolicy (CERT_CHAIN_POLICY_SSL,chain,&polparam,&status)) reason = ssl_analyze_status (GetLastError (),tmp); else if (status.dwError) reason = ssl_analyze_status (status.dwError,tmp); CertFreeCertificateChain (chain); } } if (whost) fs_give ((void **) &whost); if (reason) { /* got an error? */ /* application callback */ if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason, host,certname) ? NIL : ""; else if (*certname) { /* error message to return via mm_log() */ sprintf (buf,"*%.128s: %.255s", (*reason == '*') ? reason + 1 : reason,certname); reason = buf; } } } if (reason || (reason = ssl_analyze_status (QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))) break; /* error in certificate or getting sizes */ fs_give ((void **) &buf); /* flush temporary buffer */ /* make maximum-sized buffers */ stream->bufsize = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; if (stream->sizes.cbMaximumMessage < SSLBUFLEN) fatal ("cbMaximumMessage is less than SSLBUFLEN!"); else if (stream->sizes.cbMaximumMessage < 16384) { sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", (long) stream->sizes.cbMaximumMessage); mm_log (tmp,NIL); } stream->ibuf = (char *) fs_get (stream->bufsize); stream->obuf = (char *) fs_get (stream->bufsize); return stream; default: reason = ssl_analyze_status (e,buf); } } ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } fs_give ((void **) &buf); /* flush temporary buffer */ return stream; }
int SSL_SOCKET :: s_ssend(char* b,int sz) { // QueryContextAttributes // Encrypt Message // ssend SecPkgContext_StreamSizes Sizes; SECURITY_STATUS ss = 0; ss = QueryContextAttributes(&hCtx,SECPKG_ATTR_STREAM_SIZES,&Sizes); if (FAILED(ss)) return -1; Z<SecBuffer> Buffers(100); int mPos = 0; for(;;) { Z<char> mmsg(Sizes.cbMaximumMessage*2); Z<char> mhdr(Sizes.cbHeader*2); Z<char> mtrl(Sizes.cbTrailer*2); unsigned int dwMessage = sz - mPos; if (dwMessage == 0) break; // all ok! if (dwMessage > Sizes.cbMaximumMessage) { dwMessage = Sizes.cbMaximumMessage; } memcpy(mmsg,b + mPos,dwMessage); mPos += dwMessage; Buffers[0].pvBuffer = mhdr; Buffers[0].cbBuffer = Sizes.cbHeader; Buffers[0].BufferType = SECBUFFER_STREAM_HEADER; Buffers[2].pvBuffer = mtrl; Buffers[2].cbBuffer = Sizes.cbTrailer; Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; Buffers[3].pvBuffer = 0; Buffers[3].cbBuffer = 0; Buffers[3].BufferType = SECBUFFER_EMPTY; Buffers[1].pvBuffer = mmsg; Buffers[1].cbBuffer = dwMessage; Buffers[1].BufferType = SECBUFFER_DATA; sbin.ulVersion = SECBUFFER_VERSION; sbin.pBuffers = Buffers; sbin.cBuffers = 4; ss = EncryptMessage(&hCtx,0,&sbin,0); if (FAILED(ss)) return -1; // Send this message int rval; rval = ssend_p((char*)Buffers[0].pvBuffer,Buffers[0].cbBuffer); if (rval != Buffers[0].cbBuffer) return rval; rval = ssend_p((char*)Buffers[1].pvBuffer,Buffers[1].cbBuffer); if (rval != Buffers[1].cbBuffer) return rval; rval = ssend_p((char*)Buffers[2].pvBuffer,Buffers[2].cbBuffer); if (rval != Buffers[2].cbBuffer) return rval; } return sz; }
my_bool ma_tls_connect(MARIADB_TLS *ctls) { my_bool blocking; MYSQL *mysql; SCHANNEL_CRED Cred; MARIADB_PVIO *pvio; my_bool rc= 1; SC_CTX *sctx; SECURITY_STATUS sRet; PCCERT_CONTEXT pRemoteCertContext = NULL, pLocalCertContext= NULL; ALG_ID AlgId[MAX_ALG_ID]= {0}; if (!ctls || !ctls->pvio) return 1;; pvio= ctls->pvio; sctx= (SC_CTX *)ctls->ssl; /* Set socket to blocking if not already set */ if (!(blocking= pvio->methods->is_blocking(pvio))) pvio->methods->blocking(pvio, TRUE, 0); mysql= pvio->mysql; if (ma_tls_set_client_certs(ctls)) goto end; ZeroMemory(&Cred, sizeof(SCHANNEL_CRED)); /* Set cipher */ if (mysql->options.ssl_cipher) { WORD validTokens = 0; char *token = strtok(mysql->options.ssl_cipher, ":"); while (token) { struct st_cipher_suite *valid; for (valid = valid_ciphers; valid && valid->aid; valid++) { if (!strcmp(token, valid->cipher)) { AlgId[validTokens++] = valid->aid; break; } } token = strtok(NULL, ":"); } } Cred.palgSupportedAlgs = (ALG_ID *)&AlgId; Cred.dwVersion= SCHANNEL_CRED_VERSION; if (mysql->options.extension) Cred.dwMinimumCipherStrength = MAX(128, mysql->options.extension->tls_cipher_strength); else Cred.dwMinimumCipherStrength = 128; Cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK | SCH_SEND_ROOT_CERT | SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION; if (sctx->client_cert_ctx) { Cred.cCreds = 1; Cred.paCred = &sctx->client_cert_ctx; } if (mysql->options.extension && mysql->options.extension->tls_version) { Cred.grbitEnabledProtocols= 0; if (strstr("TLSv1.0", mysql->options.extension->tls_version)) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_0; if (strstr("TLSv1.1", mysql->options.extension->tls_version)) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_1; if (strstr("TLSv1.2", mysql->options.extension->tls_version)) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_2; } else Cred.grbitEnabledProtocols = SP_PROT_TLS1_0 | SP_PROT_TLS1_1 | SP_PROT_TLS1_2; if ((sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL)) != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); goto end; } sctx->FreeCredHdl= 1; if (ma_schannel_client_handshake(ctls) != SEC_E_OK) goto end; sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext); if (sRet != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); goto end; } if (!ma_schannel_verify_certs(sctx, 0)) goto end; return 0; end: if (pRemoteCertContext) CertFreeCertificateContext(pRemoteCertContext); if (rc && sctx->IoBufferSize) LocalFree(sctx->IoBuffer); sctx->IoBufferSize= 0; if (sctx->client_cert_ctx) CertFreeCertificateContext(sctx->client_cert_ctx); sctx->client_cert_ctx= 0; return 1; }
int SSL_SOCKET :: s_recv(char* b,int sz) { SecPkgContext_StreamSizes Sizes; SECURITY_STATUS ss = 0; ss = QueryContextAttributes(&hCtx,SECPKG_ATTR_STREAM_SIZES,&Sizes); if (FAILED(ss)) return -1; int TotalR = 0; int pI = 0; SecBuffer Buffers[5] = {0}; SecBuffer * pDataBuffer; SecBuffer * pExtraBuffer; Z<char> mmsg(Sizes.cbMaximumMessage*10); if (PendingRecvDataSize) { if (sz <= PendingRecvDataSize) { memcpy(b,PendingRecvData,sz); // Z<char> dj(PendingRecvDataSize); memcpy(dj,PendingRecvData,PendingRecvDataSize); memcpy(PendingRecvData,dj + sz,PendingRecvDataSize - sz); PendingRecvDataSize -= sz; return sz; } // else , occupied already memcpy(b,PendingRecvData,PendingRecvDataSize); sz = PendingRecvDataSize; PendingRecvDataSize = 0; return sz; } for(;;) { unsigned int dwMessage = Sizes.cbMaximumMessage; if (dwMessage > Sizes.cbMaximumMessage) dwMessage = Sizes.cbMaximumMessage; int rval = 0; if (ExtraDataSize) { memcpy(mmsg + pI,ExtraData,ExtraDataSize); pI += ExtraDataSize; ExtraDataSize = 0; } else { rval = recv_p(mmsg + pI,dwMessage); if (rval == 0 || rval == -1) return rval; pI += rval; } Buffers[0].pvBuffer = mmsg; Buffers[0].cbBuffer = pI; Buffers[0].BufferType = SECBUFFER_DATA; Buffers[1].BufferType = SECBUFFER_EMPTY; Buffers[2].BufferType = SECBUFFER_EMPTY; Buffers[3].BufferType = SECBUFFER_EMPTY; sbin.ulVersion = SECBUFFER_VERSION; sbin.pBuffers = Buffers; sbin.cBuffers = 4; ss = DecryptMessage(&hCtx,&sbin,0,NULL); if (ss == SEC_E_INCOMPLETE_MESSAGE) continue; if (ss != SEC_E_OK && ss != SEC_I_RENEGOTIATE && ss != SEC_I_CONTEXT_EXPIRED) return -1; pDataBuffer = NULL; pExtraBuffer = NULL; for (int i = 0; i < 4; i++) { if (pDataBuffer == NULL && Buffers[i].BufferType == SECBUFFER_DATA) { pDataBuffer = &Buffers[i]; } if (pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA) { pExtraBuffer = &Buffers[i]; } } if (pExtraBuffer) { ExtraDataSize = pExtraBuffer->cbBuffer; ExtraData.Resize(ExtraDataSize + 10); memcpy(ExtraData,pExtraBuffer->pvBuffer,ExtraDataSize); pI = 0; } if (ss == SEC_I_RENEGOTIATE) { ss = ClientLoop(); if (FAILED(ss)) return -1; } if (pDataBuffer == 0) break; TotalR = pDataBuffer->cbBuffer; if (TotalR <= sz) { memcpy(b,pDataBuffer->pvBuffer,TotalR); } else { TotalR = sz; memcpy(b,pDataBuffer->pvBuffer,TotalR); PendingRecvDataSize = pDataBuffer->cbBuffer - TotalR; PendingRecvData.Resize(PendingRecvDataSize + 100); PendingRecvData.clear(); memcpy(PendingRecvData,(char*)pDataBuffer->pvBuffer + TotalR,PendingRecvDataSize); } break; } return TotalR; }
static DWORD SignServer( IN INT nSocket, IN CredHandle *pServerCreds, IN ULONG AscFlags ) { DWORD dwError = ERROR_SUCCESS; ULONG ulQop = 0; INT nContextAcquired = 0; ULONG nIndex = 0; SecBuffer TransmitBuffer; SecBuffer MsgBuffer; SecBuffer WrapBuffers[2] = {0}; SecBufferDesc WrapBufferDesc; CtxtHandle Context; SecPkgContext_Names Names; SecPkgContext_Sizes Sizes; SecPkgContext_SessionKey SessionKey; memset(&TransmitBuffer, 0, sizeof(SecBuffer)); memset(&MsgBuffer, 0, sizeof(SecBuffer)); memset(&WrapBufferDesc, 0, sizeof(SecBufferDesc)); memset(&Context, 0, sizeof(CtxtHandle)); memset(&Names, 0, sizeof(SecPkgContext_Names)); memset(&Sizes, 0, sizeof(SecPkgContext_Sizes)); memset(&SessionKey, 0, sizeof(SecPkgContext_SessionKey)); /* Establish a context with the client */ dwError = ServerEstablishContext( nSocket, pServerCreds, &Context, AscFlags ); BAIL_ON_ERROR(dwError); dwError = QueryContextAttributes( &Context, SECPKG_ATTR_NAMES, &Names ); if (dwError) { printf("Unable to query context: %d\n", dwError); } else { printf("Context is for user: %s\n", Names.sUserName); } dwError = QueryContextAttributes( &Context, SECPKG_ATTR_SESSION_KEY, &SessionKey ); if (dwError) { printf("Unable to query context: %X\n", dwError); } else { printf("Session Key: "); for(nIndex = 0; nIndex < SessionKey.SessionKeyLength; nIndex++) { printf("%02X ", SessionKey.SessionKey[nIndex]); } printf("\n\n"); } printf("Server accepted context successfully!\n"); // for clean up... once we've established a context, we must clean it up on // future failures. nContextAcquired = 1; dwError = QueryContextAttributes ( &Context, SECPKG_ATTR_SIZES, &Sizes ); BAIL_ON_ERROR(dwError); /* Receive the sealed message token */ dwError = RecvToken(nSocket, &TransmitBuffer); BAIL_ON_ERROR(dwError); printf("RECEIVED:\n"); DumpBuffer(TransmitBuffer.pvBuffer, TransmitBuffer.cbBuffer); printf("\n"); WrapBufferDesc.cBuffers = 2; WrapBufferDesc.pBuffers = WrapBuffers; WrapBufferDesc.ulVersion = SECBUFFER_VERSION; WrapBuffers[0].BufferType = SECBUFFER_TOKEN; WrapBuffers[0].pvBuffer = TransmitBuffer.pvBuffer; WrapBuffers[0].cbBuffer = Sizes.cbMaxSignature; WrapBuffers[1].BufferType = SECBUFFER_DATA; WrapBuffers[1].cbBuffer = TransmitBuffer.cbBuffer - Sizes.cbMaxSignature; WrapBuffers[1].pvBuffer = (PBYTE)TransmitBuffer.pvBuffer + Sizes.cbMaxSignature; dwError = DecryptMessage( &Context, &WrapBufferDesc, 0, // no sequence number &ulQop ); if (dwError) { // When we bail, this var will try to be freed which is a bad thing... // the memory will be freed when TransmitBuffer is freed, so it's ok // to set this buffer to NULL here. WrapBuffers[1].pvBuffer = NULL; printf("Unable to decrypt message\n"); } BAIL_ON_ERROR(dwError); MsgBuffer = WrapBuffers[1]; printf("Received message '%.*s' from client\n", MsgBuffer.cbBuffer, MsgBuffer.pvBuffer); /* Produce a signature block for the message */ WrapBuffers[0] = MsgBuffer; WrapBuffers[1].BufferType = SECBUFFER_TOKEN; WrapBuffers[1].cbBuffer = Sizes.cbMaxSignature; WrapBuffers[1].pvBuffer = malloc(Sizes.cbMaxSignature); if (WrapBuffers[1].pvBuffer == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; BAIL_ON_ERROR(dwError); } dwError = MakeSignature( &Context, 0, &WrapBufferDesc, 0 ); if (dwError) { printf("Unable to MakeSignature"); } BAIL_ON_ERROR(dwError); free(TransmitBuffer.pvBuffer); TransmitBuffer = WrapBuffers[1]; WrapBuffers[1].pvBuffer = NULL; WrapBuffers[1].cbBuffer = 0; /* Send the signature block to the client */ dwError = SendToken(nSocket, &TransmitBuffer); BAIL_ON_ERROR(dwError); free(TransmitBuffer.pvBuffer); TransmitBuffer.pvBuffer = NULL; TransmitBuffer.cbBuffer = 0; /* Delete context */ dwError = DeleteSecurityContext( &Context ); BAIL_ON_ERROR(dwError); finish: return dwError; error: if (Names.sUserName) { FreeContextBuffer(Names.sUserName); } if (TransmitBuffer.pvBuffer) { free(TransmitBuffer.pvBuffer); TransmitBuffer.pvBuffer = NULL; TransmitBuffer.cbBuffer = 0; } if (WrapBuffers[1].pvBuffer) { free(WrapBuffers[1].pvBuffer); WrapBuffers[1].pvBuffer = NULL; WrapBuffers[1].cbBuffer = 0; } if (nContextAcquired) { DeleteSecurityContext(&Context); } goto finish; }
int ma_tls_verify_server_cert(MARIADB_TLS *ctls) { SC_CTX *sctx= (SC_CTX *)ctls->ssl; MARIADB_PVIO *pvio= ctls->pvio; int rc= 1; char *szName= NULL; char *pszServerName= pvio->mysql->host; /* check server name */ if (pszServerName && (sctx->mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT)) { PCCERT_CONTEXT pServerCert; DWORD NameSize= 0; char *p1, *p2; SECURITY_STATUS sRet; if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK) { ma_schannel_set_sec_error(pvio, sRet); return 1; } if (!(NameSize= CertNameToStr(pServerCert->dwCertEncodingType, &pServerCert->pCertInfo->Subject, CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, NULL, 0))) { pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate"); return 1; } if (!(szName= (char *)LocalAlloc(0, NameSize + 1))) { pvio->set_error(sctx->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL); goto end; } if (!CertNameToStr(pServerCert->dwCertEncodingType, &pServerCert->pCertInfo->Subject, CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG, szName, NameSize)) { pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Can't retrieve name of server certificate"); goto end; } if ((p1 = strstr(szName, "CN="))) { p1+= 3; if ((p2= strstr(p1, ", "))) *p2= 0; if (!strcmp(pszServerName, p1)) { rc= 0; goto end; } pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Name of server certificate didn't match"); } } end: if (szName) LocalFree(szName); return rc; }
int sserver_auth_protocol_connect(const struct protocol_interface *protocol, const char *auth_string) { CScramble scramble; char *tmp; int certonly; char *client_version = NULL; char keyfile[256]; const char *hostname = NULL; if (!strcmp (auth_string, "BEGIN SSL VERIFICATION REQUEST")) sserver_protocol_interface.verify_only = 1; else if (!strcmp (auth_string, "BEGIN SSL AUTH REQUEST")) sserver_protocol_interface.verify_only = 0; else return CVSPROTO_NOTME; write(current_server()->out_fd,SSERVER_INIT_STRING,sizeof(SSERVER_INIT_STRING)-1); if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","CertificatesOnly",keyfile,sizeof(keyfile))) certonly = atoi(keyfile); if(!CGlobalSettings::GetGlobalValue("cvsnt","PServer","ServerDnsName",keyfile,sizeof(keyfile))) hostname = keyfile; if(!ServerAuthenticate(hostname)) return CVSPROTO_AUTHFAIL; QueryContextAttributes(&contextHandle,SECPKG_ATTR_STREAM_SIZES,&secSizes); g_sslBufferInPos=g_sslBufferOutPos=0; g_sslBufferInLen=g_sslBufferOutLen=0; set_encrypted_channel(1); /* Error must go through us now */ PCERT_CONTEXT sc; PCCERT_CHAIN_CONTEXT pcc; CERT_SIMPLE_CHAIN *psc; CERT_CHAIN_PARA para = { sizeof(CERT_CHAIN_PARA) }; DWORD trust,rc; BOOL cert = FALSE; rc = QueryContextAttributes(&contextHandle,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&sc); if(rc && rc!=SEC_E_NO_CREDENTIALS) server_error(1,"Couldn't get client certificate"); if(rc!=SEC_E_NO_CREDENTIALS) /* The client doesn't have to send us a cert. as cvs uses passwords normally */ { if(!CertGetCertificateChain(NULL, sc, NULL, NULL, ¶, 0, NULL, &pcc)) server_error(1,"Couldn't get client certificate chain"); psc = pcc->rgpChain[0]; trust = psc->TrustStatus.dwErrorStatus; if (trust) { if (trust & (CERT_TRUST_IS_PARTIAL_CHAIN | CERT_TRUST_IS_UNTRUSTED_ROOT)) server_error(1,"Client sent self signed certificate"); else if (trust & (CERT_TRUST_IS_NOT_TIME_VALID)) server_error(1,"Client certificate expired"); else server_error(1,"Client certificate verification failed - %08x",trust); } CertFreeCertificateChain(pcc); FreeContextBuffer(sc); cert = TRUE; } /* Get the three important pieces of information in order. */ /* See above comment about error handling. */ /* get version, if sent. 1.0 clients didn't have this handshake so we have to handle that. */ server_getline (protocol, &client_version, MAX_PATH); if(strncmp(client_version,"SSERVER-CLIENT ",15)) { sserver_protocol_interface.auth_repository = client_version; client_version = NULL; } else server_getline (protocol, &sserver_protocol_interface.auth_repository, MAX_PATH); server_getline (protocol, &sserver_protocol_interface.auth_username, MAX_PATH); server_getline (protocol, &sserver_protocol_interface.auth_password, MAX_PATH); if(client_version) free(client_version); client_version = NULL; /* ... and make sure the protocol ends on the right foot. */ /* See above comment about error handling. */ server_getline(protocol, &tmp, MAX_PATH); if (strcmp (tmp, sserver_protocol_interface.verify_only ? "END SSL VERIFICATION REQUEST" : "END SSL AUTH REQUEST") != 0) { server_printf ("bad auth protocol end: %s\n", tmp); free(tmp); return CVSPROTO_FAIL; } strcpy(sserver_protocol_interface.auth_password, scramble.Unscramble(sserver_protocol_interface.auth_password)); free(tmp); switch(certonly) { case 0: break; case 1: if(!cert) { server_error(0,"E Login requires a valid client certificate.\n"); return CVSPROTO_AUTHFAIL; } free(sserver_protocol_interface.auth_password); sserver_protocol_interface.auth_password = NULL; break; case 2: if(!cert) { server_error(0,"E Login requires a valid client certificate.\n"); return CVSPROTO_AUTHFAIL; } break; }; return CVSPROTO_SUCCESS; }
char* CompleteGssapi(HANDLE hSecurity, unsigned char *szChallenge, unsigned chlsz) { if (!szChallenge || !szChallenge[0]) return NULL; NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity; unsigned char inDataBuffer[1024]; SecBuffer inBuffers[2] = { { sizeof(inDataBuffer), SECBUFFER_DATA, inDataBuffer }, { chlsz, SECBUFFER_STREAM, szChallenge } }; SecBufferDesc inBuffersDesc = { SECBUFFER_VERSION, 2, inBuffers }; unsigned long qop = 0; SECURITY_STATUS sc = DecryptMessage(&hNtlm->hClientContext, &inBuffersDesc, 0, &qop); if (sc != SEC_E_OK) { ReportSecError(sc, __LINE__); return NULL; } // unsigned char LayerMask = inDataBuffer[0]; // unsigned int MaxMessageSize = htonl(*(unsigned*)&inDataBuffer[1]); SecPkgContext_Sizes sizes; sc = QueryContextAttributes(&hNtlm->hClientContext, SECPKG_ATTR_SIZES, &sizes); if (sc != SEC_E_OK) { ReportSecError(sc, __LINE__); return NULL; } unsigned char *tokenBuffer = (unsigned char*)alloca(sizes.cbSecurityTrailer); unsigned char *paddingBuffer = (unsigned char*)alloca(sizes.cbBlockSize); unsigned char outDataBuffer[4] = { 1, 0, 16, 0 }; SecBuffer outBuffers[3] = { { sizes.cbSecurityTrailer, SECBUFFER_TOKEN, tokenBuffer }, { sizeof(outDataBuffer), SECBUFFER_DATA, outDataBuffer }, { sizes.cbBlockSize, SECBUFFER_PADDING, paddingBuffer } }; SecBufferDesc outBuffersDesc = { SECBUFFER_VERSION, 3, outBuffers }; sc = EncryptMessage(&hNtlm->hClientContext, SECQOP_WRAP_NO_ENCRYPT, &outBuffersDesc, 0); if (sc != SEC_E_OK) { ReportSecError(sc, __LINE__); return NULL; } unsigned i, ressz = 0; for (i = 0; i < outBuffersDesc.cBuffers; i++) ressz += outBuffersDesc.pBuffers[i].cbBuffer; unsigned char *response = (unsigned char*)alloca(ressz), *p = response; for (i = 0; i < outBuffersDesc.cBuffers; i++) { memcpy(p, outBuffersDesc.pBuffers[i].pvBuffer, outBuffersDesc.pBuffers[i].cbBuffer); p += outBuffersDesc.pBuffers[i].cbBuffer; } return mir_base64_encode(response, ressz); }
static int send_chunk(CONCRETE_IO_HANDLE tls_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context) { int result; if ((tls_io == NULL) || (buffer == NULL) || (size == 0)) { /* Invalid arguments */ result = __LINE__; } else { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io; if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN) { result = __LINE__; } else { SecPkgContext_StreamSizes sizes; SECURITY_STATUS status = QueryContextAttributes(&tls_io_instance->security_context, SECPKG_ATTR_STREAM_SIZES, &sizes); if (status != SEC_E_OK) { result = __LINE__; } else { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; size_t needed_buffer = sizes.cbHeader + size + sizes.cbTrailer; unsigned char* out_buffer = (unsigned char*)malloc(needed_buffer); if (out_buffer == NULL) { result = __LINE__; } else { memcpy(out_buffer + sizes.cbHeader, buffer, size); security_buffers[0].BufferType = SECBUFFER_STREAM_HEADER; security_buffers[0].cbBuffer = sizes.cbHeader; security_buffers[0].pvBuffer = out_buffer; security_buffers[1].BufferType = SECBUFFER_DATA; security_buffers[1].cbBuffer = size; security_buffers[1].pvBuffer = out_buffer + sizes.cbHeader; security_buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; security_buffers[2].cbBuffer = sizes.cbTrailer; security_buffers[2].pvBuffer = out_buffer + sizes.cbHeader + size; security_buffers[3].cbBuffer = 0; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers[3].pvBuffer = 0; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; status = EncryptMessage(&tls_io_instance->security_context, 0, &security_buffers_desc, 0); if (FAILED(status)) { result = __LINE__; } else { if (xio_send(tls_io_instance->socket_io, out_buffer, security_buffers[0].cbBuffer + security_buffers[1].cbBuffer + security_buffers[2].cbBuffer, on_send_complete, callback_context) != 0) { result = __LINE__; } else { size_t i; for (i = 0; i < size; i++) { LOG(tls_io_instance->logger_log, 0, "%02x-> ", ((unsigned char*)buffer)[i]); } LOG(tls_io_instance->logger_log, LOG_LINE, ""); result = 0; } } free(out_buffer); } } } } return result; }
SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls) { MARIADB_PVIO *pvio; SECURITY_STATUS sRet; DWORD OutFlags; DWORD r; SC_CTX *sctx; SecBuffer ExtraData; DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; SecBufferDesc BufferOut; SecBuffer BuffersOut; if (!ctls || !ctls->pvio) return 1; pvio= ctls->pvio; sctx= (SC_CTX *)ctls->ssl; /* Initialie securifty context */ BuffersOut.BufferType= SECBUFFER_TOKEN; BuffersOut.cbBuffer= 0; BuffersOut.pvBuffer= NULL; BufferOut.cBuffers= 1; BufferOut.pBuffers= &BuffersOut; BufferOut.ulVersion= SECBUFFER_VERSION; sRet = InitializeSecurityContext(&sctx->CredHdl, NULL, pvio->mysql->host, SFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sctx->ctxt, &BufferOut, &OutFlags, NULL); if(sRet != SEC_I_CONTINUE_NEEDED) { ma_schannel_set_sec_error(pvio, sRet); return sRet; } /* send client hello packaet */ if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL) { r= (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer); if (r <= 0) { sRet= SEC_E_INTERNAL_ERROR; goto end; } } sRet= ma_schannel_handshake_loop(pvio, TRUE, &ExtraData); /* allocate IO-Buffer for write operations: After handshake was successfull, we are able now to calculate payload */ if ((sRet = QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes ))) goto end; sctx->IoBufferSize= SCHANNEL_PAYLOAD(sctx->Sizes); if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(0, sctx->IoBufferSize))) { sRet= SEC_E_INSUFFICIENT_MEMORY; goto end; } return sRet; end: LocalFree(sctx->IoBuffer); sctx->IoBufferSize= 0; FreeContextBuffer(BuffersOut.pvBuffer); DeleteSecurityContext(&sctx->ctxt); return sRet; }