Carregar um PEM codificado certificado X.509 no Windows CryptoAPI
-
22-07-2019 - |
Pergunta
Eu preciso carregar um PEM codificado X.509 certificado em um contexto Windows API Crypto para usar com C ++. Eles são os únicos que têm -----BEGIN RSA XXX KEY-----
e -----END RSA XXX KEY-----
. Eu encontrei exemplos para Python e .NET, mas eles usam funções específicas que não podem se relacionar com a planície API do Windows Crypto.
Eu entendo como para criptografar / descriptografar uma vez que eu tenho uma HCRYPTKEY.
MAS, eu simplesmente não entendo como importar o blob Base64 no arquivo .PEM (s) e obter um HCRYPTKEY
que eu posso usar fora dele.
Eu tenho essa estranha sensação de que há mais do que simplesmente chamando CryptDecodeObject()
.
Os ponteiros que podem me colocar no caminho certo? Eu já perdi dois dias fazendo "tentativa e erro" de programação e chegando a lugar nenhum.
Solução
KJKHyperion disse em sua resposta :
Eu descobri a seqüência de "mágica" de chamadas para importar uma chave pública RSA no formato PEM. Aqui vai:
- decodificar a chave em um blob binário com CryptStringToBinary ; passar CRYPT_STRING_BASE64HEADER na dwFlags
- decodificar o blob de chave binário em um CERT_PUBLIC_KEY_INFO com CryptDecodeObjectEx ; passar X509_ASN_ENCODING em dwCertEncodingType e X509_PUBLIC_KEY_INFO em lpszStructType
- decodificar o blob PublicKey do CERT_PUBLIC_KEY_INFO em um blob de chave RSA com CryptDecodeObjectEx ; passar X509_ASN_ENCODING em dwCertEncodingType e RSA_CSP_PUBLICKEYBLOB em lpszStructType
- importar o blob de chave RSA com CryptImportKey
Esta seqüência realmente me ajudou a entender o que está acontecendo, mas não funcionou para mim como está. A segunda chamada para CryptDecodeObjectEx
deu-me um erro:
"ASN.1 mau valor tag conheci".
Depois de muitas tentativas de documentação compreensão Microsoft, eu finalmente percebi que a saída do decodificação punho não pode ser decodificado como ASN novamente, e que ele está realmente pronto para importação. Com esse entendimento, eu encontrei a resposta no link a seguir:
http: //www.ms-news .net / f2748 / importadores de problema-chave pública-4052577.html
A seguir é o meu próprio programa que as importações uma chave pública a partir de um arquivo .pem a um contexto cryptapi:
int main()
{
char pemPubKey[2048];
int readLen;
char derPubKey[2048];
size_t derPubKeyLen = 2048;
CERT_PUBLIC_KEY_INFO *publicKeyInfo;
int publicKeyInfoLen;
HANDLE hFile;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
/*
* Read the public key cert from the file
*/
hFile = CreateFileA( "c:\\pub.pem", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile == INVALID_HANDLE_VALUE )
{
fprintf( stderr, "Failed to open file. error: %d\n", GetLastError() );
}
if ( !ReadFile( hFile, pemPubKey, 2048, &readLen, NULL ) )
{
fprintf( stderr, "Failed to read file. error: %d\n", GetLastError() );
}
/*
* Convert from PEM format to DER format - removes header and footer and decodes from base64
*/
if ( !CryptStringToBinaryA( pemPubKey, 0, CRYPT_STRING_BASE64HEADER, derPubKey, &derPubKeyLen, NULL, NULL ) )
{
fprintf( stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError() );
}
/*
* Decode from DER format to CERT_PUBLIC_KEY_INFO
*/
if ( !CryptDecodeObjectEx( X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPubKey, derPubKeyLen,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen ) )
{
fprintf( stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError() );
return -1;
}
/*
* Acquire context
*/
if( !CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) )
{
{
printf( "CryptAcquireContext failed - err=0x%x.\n", GetLastError() );
return -1;
}
}
/*
* Import the public key using the context
*/
if ( !CryptImportPublicKeyInfo( hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey ) )
{
fprintf( stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError() );
return -1;
}
LocalFree( publicKeyInfo );
/*
* Now use hKey to encrypt whatever you need.
*/
return 0;
}
Outras dicas
Eu descobri a seqüência de "mágica" de chamadas para importar uma chave pública RSA no formato PEM. Aqui vai:
- decodificar a chave em um blob binário com CryptStringToBinary ; passar CRYPT_STRING_BASE64HEADER na dwFlags
- decodificar o blob de chave binário em um CERT_PUBLIC_KEY_INFO com CryptDecodeObjectEx ; passar X509_ASN_ENCODING em dwCertEncodingType e X509_PUBLIC_KEY_INFO em lpszStructType
- decodificar o blob PublicKey do CERT_PUBLIC_KEY_INFO em um blob de chave RSA com CryptDecodeObjectEx ; passar X509_ASN_ENCODING em dwCertEncodingType e RSA_CSP_PUBLICKEYBLOB em lpszStructType
- importar o blob de chave RSA com CryptImportKey
Atualmente estou enfrentando a mesma dificuldade. Eu não terminei de codificação uma solução, mas como eu entendo que é preciso retirar a ----- BEGIN etc ----- e ----- END etc ------ tags e decodificar a Base64 .
Isso deixa você com uma corda DER codificado, o que você precisa analisar para obter o módulo e expoente público. Daqueles que você pode preencher as estruturas PUBLICKEYSTRUC e RSAPUBKEY. Boa sorte; -)