Charger un certificat X.509 codé PEM dans Windows CryptoAPI
-
22-07-2019 - |
Question
Je dois charger un certificat X.509 codé PEM dans un contexte API Windows Crypto à utiliser avec C ++. Ce sont ceux qui ont ----- BEGIN RSA XXX KEY -----
et ----- END RSA XXX KEY -----
. J'ai trouvé des exemples pour Python et .NET, mais ils utilisent des fonctions spécifiques que je ne peux pas relier à l'API Windows Crypto.
Je comprends comment chiffrer / déchiffrer une fois que j'ai un HCRYPTKEY.
MAIS, je ne comprends pas comment importer le blob Base64 dans le (s) fichier (s) .PEM et obtenir un HCRYPTKEY
que je peux utiliser.
J'ai ce sentiment étrange qu'il ne s'agit pas simplement d'appeler CryptDecodeObject ()
.
Des indicateurs qui peuvent me mettre sur la bonne voie? J'ai déjà perdu deux jours à "essayer". erreur " programmation et obtenir nulle part.
La solution
KJKHyperion a déclaré dans son répondre :
J'ai découvert le "magique". séquence d'appels pour importer une clé publique RSA au format PEM. Ici vous allez:
- décodez la clé en un objet blob binaire avec CryptStringToBinary ; transmettez CRYPT_STRING_BASE64HEADER dans dwFlags
- décodez le blob de clé binaire en un CERT_PUBLIC_KEY_INFO avec CryptDecodeObjectEx ; transmettez X509_ASN_ENCODING à dwCertEncodingType et X509_PUBLIC_KEY_INFO à lpszStructType
- décodez le blob PublicKey du CERT_PUBLIC_KEY_INFO en un blob de clé RSA avec CryptDecodeObjectEx ; transmettez X509_ASN_ENCODING dans dwCertEncodingType et RSA_CSP_PUBLICKEYBLOB dans lpszStructType
- importer le blob de clé RSA avec CryptImportKey
Cette séquence m'a vraiment aidé à comprendre ce qui se passe, mais cela n'a pas fonctionné pour moi tel quel. Le deuxième appel à CryptDecodeObjectEx
m'a donné une erreur:
"Valeur de balise ASN.1 incorrecte atteinte".
Après de nombreuses tentatives pour comprendre la documentation Microsoft, j'ai finalement compris que la sortie du premier décodage ne pouvait plus être décodée en tant qu'ASN et qu'elle était prête à être importée. Avec cette compréhension, j'ai trouvé la réponse dans le lien suivant:
http: //www.ms-news .net / f2748 / problème-importation-clé-publique-4052577.html
Voici mon propre programme qui importe une clé publique d'un fichier .pem vers un contexte 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;
}
Autres conseils
J'ai découvert le "magique". séquence d'appels pour importer une clé publique RSA au format PEM. Ici vous allez:
- décodez la clé en un objet blob binaire avec CryptStringToBinary ; transmettez CRYPT_STRING_BASE64HEADER dans dwFlags
- décodez le blob de clé binaire en un CERT_PUBLIC_KEY_INFO avec CryptDecodeObjectEx ; transmettez X509_ASN_ENCODING à dwCertEncodingType et X509_PUBLIC_KEY_INFO à lpszStructType
- décodez le blob PublicKey du CERT_PUBLIC_KEY_INFO en un blob de clé RSA avec CryptDecodeObjectEx ; transmettez X509_ASN_ENCODING dans dwCertEncodingType et RSA_CSP_PUBLICKEYBLOB dans lpszStructType
- importer le blob de clé RSA avec CryptImportKey
Je suis actuellement confronté à la même difficulté. Je n'ai pas fini de coder une solution, mais si j'ai bien compris, vous devez retirer les balises ----- COMMENCER etc. ----- et ----- END etc. ------ et décoder la Base64. .
Cela vous laisse avec une chaîne codée DER, que vous devez analyser pour obtenir le module et l’exposant public. À partir de celles-ci, vous pouvez renseigner les structures PUBLICKEYSTRUC et RSAPUBKEY. Bonne chance ;-)