Import d’un certificat d’autorité dans le service de certificats Microsoft

! Attention, cet article peut paraître totalement aberrant aux lecteurs connaissant les HSM !

Si vous avez généré votre biclé sur un système tiers plutôt que sur le serveur d’autorité Microsoft, il va falloir l’importer lors de l’installation ou du renouvellement…
Si certains messages d’erreurs lors de cet import peuvent être explicites, d’autres sont plus déconcertants :
import_p12
Le certificat sélectionné n’a pas pu être utilisé

Ou lors de l’import dans la console de certificats :
import_re_p12
ASN1 fin de données inattendue. 0x80093102 (ASN: 258)

Pourtant ce certificat peut très bien être utilisé par l’autorité…
Malgré ce Windows trop sur de lui, ce n’est pas le certificat qui ne peut être utilisé, mais le conteneur PKCS#12 qui ne contient pas les données attendues par le service…

Voici les attributs de clé contenu dans notre « P12 », précédemment généré par OpenSSL, xca ou autres logiciels cryptographique digne de ce nom :

Offset| Len  |LenByte|
======+======+=======+======================================================================
  4195|    62|      1| SET : 
  4197|    23|      1|    SEQUENCE : 
  4199|     9|      1|       OBJECT IDENTIFIER : friendlyName [1.2.840.113549.1.9.20]
  4210|    10|      1|       SET : 
  4212|     8|      1|          BMP STRING : 'acms'
  4222|    35|      1|    SEQUENCE : 
  4224|     9|      1|       OBJECT IDENTIFIER : localKeyID [1.2.840.113549.1.9.21]
  4235|    22|      1|       SET : 
  4237|    20|      1|          OCTET STRING : 
      |      |       |             9A499BFB3E6AACE88638381E253C15190BC16FDD

ou via OpenSSL :

Bag Attributes
    friendlyName: acms
    localKeyID: 9A 49 9B FB 3E 6A AC E8 86 38 38 1E 25 3C 15 19 0B C1 6F DD 
Key Attributes: <No Attributes>

Pour n’importe quel autre logiciel cryptographique, cela suffirait amplement…. mais non, Microsoft semble rester sur sa faim avec ce P12…
Reconstruisons un autre avec le même certificat, la même clé, mais avec d’autres attributs :

  • Local Machine Keyset (-LMK)
  • Cryptographic Service Providers (-CSP x)
  • Friendly Name (-name)

Le fichier .p12 est conservé, un nouveau .pfx est créé.

openssl pkcs12 -password pass:XXXX -in acms.p12 -out acms.pem -clcerts -nodes
openssl pkcs12 -in acms.pem -password pass:XXXX -out acms.pfx -name "ac ms" -CSP "Microsoft Software Key Storage Provider" -LMK -export

Remarques :

  • ne pas oublier de supprimer minutieusement le fichier acms.pem
  • Le fournisseur « Microsoft Software Key Storage Provider » n’est disponible que sous NT 6, il doit malheureusement être remplacé par « Microsoft Enhanced RSA and AES Cryptographic Provider » avant

Voici les nouveaux attributs de clé :

Offset| Len  |LenByte|
======+======+=======+======================================================================
  4195|   174|      2| SET : 
  4198|    13|      1|    SEQUENCE : 
  4200|     9|      1|       OBJECT IDENTIFIER :  [1.3.6.1.4.1.311.17.2]
  4211|     0|      1|       SET : ''
  4213|    25|      1|    SEQUENCE : 
  4215|     9|      1|       OBJECT IDENTIFIER : friendlyName [1.2.840.113549.1.9.20]
  4226|    12|      1|       SET : 
  4228|    10|      1|          BMP STRING : 'ac ms'
  4240|    35|      1|    SEQUENCE : 
  4242|     9|      1|       OBJECT IDENTIFIER : localKeyID [1.2.840.113549.1.9.21]
  4253|    22|      1|       SET : 
  4255|    20|      1|          OCTET STRING : 
      |      |       |             9A499BFB3E6AACE88638381E253C15190BC16FDD
  4277|    93|      1|    SEQUENCE : 
  4279|     9|      1|       OBJECT IDENTIFIER : szOID_LOCAL_MACHINE_KEYSET [1.3.6.1.4.1.311.17.1]
  4290|    80|      1|       SET : 
  4292|    78|      1|          BMP STRING : 
      |      |       |             'Microsoft Software Key Storage Provider'

ou via OpenSSL :

Bag Attributes
    Microsoft Local Key set: <No Values>
    friendlyName: ac ms
    localKeyID: 9A 49 9B FB 3E 6A AC E8 86 38 38 1E 25 3C 15 19 0B C1 6F DD 
    Microsoft CSP Name: Microsoft Software Key Storage Provider
Key Attributes: <No Attributes>

Cette fois, le PFX est correctement importé et utilisable. Le cas échéant, il faudra aller supprimer l’ancien certificat déjà importé.

Question de sécurité : Windows conserve-t-il la clé privée lors de la suppression d’un certificat ?

A vide, sans certificat

Du point de vue de certutil

c:\temp>certutil -user -store my
CertUtil: -store La commande s'est terminée correctement.

c:\temp>certutil -store my
CertUtil: -store La commande s'est terminée correctement.

Du point de vue des conteneurs de clés

c:\temp>pkconteneurs
Conteneur(s) utilisateur :
Conteneur(s) machine :

Avec des certificats…

Installation de deux certificats (un dans le magasin utilisateur, l’autre machine)

c:\temp>certutil -user -p password -importpfx user.p12
c:\temp>certutil -p password -importpfx machine.p12

Du point de vue de certutil

c:\temp>certutil -user -store my
================ Certificat 0 ================
Objet: CN=user_export_noprotect
Conteneur de clé = user_export_noprotect-050c8772-126a-4815-8de8-0d3b27dda6e1

c:\temp>certutil -store my
================ Certificat 0 ================
Objet: CN=machine_export_noprotect
Conteneur de clé = machine_export_noprotect-69edbe24-fc12-43ff-ae70-7fa3ce723058

Du point de vue des conteneurs de clés

c:\temp>pkconteneurs
Conteneur(s) utilisateur :
user_export_noprotect-050c8772-126a-4815-8de8-0d3b27dda6e1
Conteneur(s) machine :
machine_export_noprotect-69edbe24-fc12-43ff-ae70-7fa3ce723058

A vide, en ayant supprimé les certificats

Suppression des certificats précédemment importés

c:\temp>certutil -user -delstore my "user_export_noprotect"
Suppression du certificat 0

c:\temp>certutil -delstore my "machine_export_noprotect"
Suppression du certificat 0

Du point de vue de certutil

c:\temp>certutil -user -store my
CertUtil: -store La commande s'est terminée correctement.

c:\temp>certutil -store my
CertUtil: -store La commande s'est terminée correctement.

Du point de vue des conteneurs de clés

c:\temp>pkconteneurs
Conteneur(s) utilisateur :
user_export_noprotect-050c8772-126a-4815-8de8-0d3b27dda6e1
Conteneur(s) machine :
machine_export_noprotect-69edbe24-fc12-43ff-ae70-7fa3ce723058

Conclusion

Il semblerait que les conteneurs des clés privées des certificats précédemment importés soient encore présent…
Astuce disponible dans mimikatz (export des clés privées orphelines) !

Code de l’éxecutable : pkconteneurs

#pragma comment(lib, "advapi32.lib")

#include <windows.h>
#include <iostream>

using namespace std;

void listContainers(bool isMachine)
{
	DWORD flags = CRYPT_VERIFYCONTEXT | (isMachine ? CRYPT_MACHINE_KEYSET : NULL);

	HCRYPTPROV hCryptProv = NULL;
	if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, flags))
	{
		DWORD buflen = 0;
		if(CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, NULL, &buflen, CRYPT_FIRST))
		{
			char * cname = new char[buflen];
			for (DWORD idx = 0;;idx++)
			{
				if(CryptGetProvParam(hCryptProv, PP_ENUMCONTAINERS, reinterpret_cast<BYTE *>(cname), &buflen, (idx == 0 ? CRYPT_FIRST : CRYPT_NEXT)))
				{
					wcout << cname << endl;
				}
				else
				{
					break;
				}
			}
			delete[] cname;
		}
	}
	CryptReleaseContext(hCryptProv, 0);
}

int wmain(int argc, wchar_t * argv[])
{
	wcout << L"Conteneur(s) utilisateur :" << endl << endl;
	listContainers(false);
	wcout << endl;
	
	wcout << L"Conteneur(s) machine :" << endl << endl;
	listContainers(true);
	wcout << endl;

	return ERROR_SUCCESS;
}