Cryptographie rapide sous Windows

Comment obtenir un hash MD5 sous Windows, déchiffrer un bloc DES ?

j’ai totalement conscience d’évoquer dans ce post des algorithmes considérés comme dépassés, mais ces derniers sont toujours massivement utilisés dans les mécanismes internes de Windows
mimikatz 2.0 s’en sert lui aussi massivement ;)

Limitations

Les algorithmes évoqués dans ce post sont seulement les suivants :

MD4 LM DES (ECB)
MD5 NTLM RC4
SHA1    

Déjà vu sur Internet *

  • assemblage de bouts de code provenant d’Internet (réimplémentation des algorithmes)
  • utilisation des librairies d’OpenSSL
  • utilisation de la CryptoAPI
  • utilisation de la CNG

* je passe sur l’utilisation de CSP/PKCS#11 pour communiquer avec son HSM préféré ;)

A notre disposition sous Windows

Comme déjà listé, il est possible d’utiliser nativement la CryptoAPI, ou sa nouvelle version la CNG… mais n’est-ce-pas un peu lourd pour de si simples besoins ?

Windows incorpore déjà beaucoup de routines dans ses librairies système et, si l’on en utilise une grande partie via les SDK référençant ces API, l’on en occulte quelques-unes très pratiques !

Une majorité de ces API se situent dans la librairie advapi32.

API clairement identifiées

MD4Init MD5Init A_SHAInit
MD4Update MD5Update A_SHAUpdate
MD4Final MD5Final A_SHAFinal

API derrières SystemFunctionXXX

RtlEncryptDES1block1key SystemFunction001
RtlDecryptDES1block1key SystemFunction002
RtlEncryptDESMagicBlock1key SystemFunction003
RtlEncryptDESblocksECB SystemFunction004
RtlDecryptDESblocksECB SystemFunction005
RtlDigestLM SystemFunction006
RtlDigestNTLM SystemFunction007
RtlLMResponseToChallenge
NTLMv1 aussi sans doute
SystemFunction008
SystemFunction009
RtlDigestMD4only16Bytes SystemFunction010
SystemFunction011
RtlEncryptDES2blocks2keys SystemFunction012
SystemFunction014
SystemFunction020
SystemFunction022
RtlDecryptDES2blocks2keys SystemFunction013
SystemFunction015
SystemFunction021
SystemFunction023
RtlEncryptDES2blocks1key SystemFunction016
SystemFunction018
RtlDecryptDES2blocks1key SystemFunction017
SystemFunction019
RtlEncryptDES2blocks1DWORD SystemFunction024
SystemFunction026
RtlDecryptDES2blocks1DWORD SystemFunction025
SystemFunction027
RtlEqualMemory16Bytes SystemFunction030
SystemFunction031
RtlEncryptDecryptRC4 SystemFunction032
SystemFunction033
RtlCheckSignatureInFile SystemFunction035
Clé de session RPC
fonctions non identiques
SystemFunction028
SystemFunction029
SystemFunction034

Téléchargement

La majorité des API sont référencées via des SystemFunctionXXX qui peuvent déjà être liées par la librairie advapi32.lib du SDK ou WDK.

Malheureusement pas les API A_SHAFinal, A_SHAInit, A_SHAUpdate, MD4Final, MD4Init, MD4Update, MD5Final, MD5Init, MD5Update et RtlCheckSignatureInFile (SystemFunction035).

J’ai donc créé trois fichiers :

Exemple de petit code

Il est là pour exposer l’utilisation du CRYPTO_BUFFER, du MD5, SHA1 et DES-ECB

const BYTE data[] = "my super secret is a kiwi :)";
const BYTE key[] = "42 & 0xdeadbeef of course !";

CRYPTO_BUFFER
	bData    = {sizeof(data) - 1, sizeof(data) - 1, (PBYTE) data}, 
	bKey     = {sizeof(key) - 1, sizeof(key) - 1, (PBYTE) key},
	bCipData = {0, 0, NULL},
	bDecData = {0, 0, NULL}
;

MD5_CTX md5ctxInput, md5ctxOutput; // MD5 digest in context
SHA_CTX shactxInput, shactxOutput;
SHA_DIGEST shaInput, shaOutput;

NTSTATUS status;

MD5Init(&md5ctxInput);
MD5Update(&md5ctxInput, bData.Buffer, bData.Length);
MD5Final(&md5ctxInput);	// original data MD5 hash

A_SHAInit(&shactxInput);
A_SHAUpdate(&shactxInput, bData.Buffer, bData.Length);
A_SHAFinal(&shactxInput, &shaInput); // original data SHA1 hash

status = RtlEncryptDESblocksECB(&bData, &bKey, &bCipData);
if(status == STATUS_BUFFER_TOO_SMALL)
{
	if(bCipData.Buffer = (PBYTE) LocalAlloc(LPTR, bCipData.Length))
	{
		bCipData.MaximumLength = bCipData.Length;
		status = RtlEncryptDESblocksECB(&bData, &bKey, &bCipData);
	}
} else status = STATUS_NONCONTINUABLE_EXCEPTION;

if(NT_SUCCESS(status)) // Cipher operation OK ?
{
	status = RtlDecryptDESblocksECB(&bCipData, &bKey, &bDecData);
	if(status == STATUS_BUFFER_TOO_SMALL)
	{
		if(bDecData.Buffer = (PBYTE) LocalAlloc(LPTR, bDecData.Length))
		{
			bDecData.MaximumLength = bDecData.Length;
			status = RtlDecryptDESblocksECB(&bCipData, &bKey, &bDecData);
		}
	} else status = STATUS_NONCONTINUABLE_EXCEPTION;
} 

if(NT_SUCCESS(status)) // Decipher operation OK ?
{
	MD5Init(&md5ctxOutput);
	MD5Update(&md5ctxOutput, bDecData.Buffer, bDecData.Length);
	MD5Final(&md5ctxOutput); // deciphered data MD5 hash

	A_SHAInit(&shactxOutput);
	A_SHAUpdate(&shactxOutput, bDecData.Buffer, bDecData.Length);
	A_SHAFinal(&shactxOutput, &shaOutput); // deciphered data SHA1 hash
		
	// data compare works too, but it's for expose MD5 & SHA1 functions ;)
	wprintf(L"MD5  match : %s\n",
		RtlEqualMemory(md5ctxInput.digest, md5ctxOutput.digest, MD5_DIGEST_LENGTH) ? L"OK" : L"KO");
	wprintf(L"SHA1 match : %s\n",
		RtlEqualMemory(shaInput.digest, shaOutput.digest, SHA_DIGEST_LENGTH) ? L"OK" : L"KO");
}

LocalFree(bDecData.Buffer);
LocalFree(bCipData.Buffer);

Correction d’un en-tête Windows

Les seules API un tant soit peu présentes dans les en-têtes standards de Windows sont les suivantes :

  • RtlEncryptMemory
  • RtlDecryptMemory
  • RtlGenRandom

Lors de l’utilisation de ces fonctions, avec les fichiers proposés ou non, si les erreurs suivantes apparaissent lors de la création des liens :

error LNK2001: symbole externe non résolu _SystemFunction036
error LNK2001: symbole externe non résolu _SystemFunction040
error LNK2001: symbole externe non résolu _SystemFunction041

C’est que l’en-tête ntsecapi.h déclare incorrectement les prototypes des fonctions.
Il faut malheureusement les corriger :

BOOLEAN
RtlGenRandom(
    __out_bcount(RandomBufferLength) PVOID RandomBuffer,
    __in ULONG RandomBufferLength
    );
//...
NTSTATUS
RtlEncryptMemory(
    __inout_bcount(MemorySize) PVOID Memory,
    __in ULONG MemorySize,
    __in ULONG OptionFlags
    );

NTSTATUS
RtlDecryptMemory(
    __inout_bcount(MemorySize) PVOID Memory,
    __in ULONG MemorySize,
    __in ULONG OptionFlags
    );

en rajoutant la convention d’appel WINAPI (__stdcall) :

BOOLEAN WINAPI
RtlGenRandom(
    __out_bcount(RandomBufferLength) PVOID RandomBuffer,
    __in ULONG RandomBufferLength
    );
//...
NTSTATUS WINAPI
RtlEncryptMemory(
    __inout_bcount(MemorySize) PVOID Memory,
    __in ULONG MemorySize,
    __in ULONG OptionFlags
    );

NTSTATUS WINAPI
RtlDecryptMemory(
    __inout_bcount(MemorySize) PVOID Memory,
    __in ULONG MemorySize,
    __in ULONG OptionFlags
    );

Signer rapidement quelques programmes

Avec les outils de Visual Studio (ou du SDK) :

signtool sign /v ^
/d "mimikatz 1.0 (alpha)" /du "http://blog.gentilkiwi.com/mimikatz" ^
/sha1 ab9e92b943ed47d915bc26939e24a58303acaa7e ^
/t http://timestamp.globalsign.com/scripts/timstamp.dll ^
c:\security\mimikatz\Win32\*.exe c:\security\mimikatz\Win32\*.dll ^
c:\security\mimikatz\x64\*.exe c:\security\mimikatz\x64\*.dll

Cela donne une belle signature :
sign_kiwi
Plus d’informations : http://msdn.microsoft.com/library/aa387764.aspx

Avec les outils Java :

jarsigner -verbose ^
-storetype Windows-MY -providername SunMSCAPI ^
-tsa http://timestamp.globalsign.com/scripts/timstamp.dll ^
kdc.jar "Benjamin Delpy"

Plus d’informations : http://download.oracle.com/javase/6/docs/technotes/tools/windows/jarsigner.html

Quelques services d’horodatages :

  • http://timestamp.globalsign.com/scripts/timstamp.dll
  • http://timestamp.verisign.com/scripts/timstamp.dll (ne fonctionne pas en Java…)
  • http://timestamp.comodoca.com/authenticode (ne fonctionne pas en Java…)

Visiblement Verisign et Comodo préfèrent se passer de la RFC 3161 (http://www.ietf.org/rfc/rfc3161.txt) qui indique que les communications sur HTTP doivent se faire en DER avec les mimetypes appropriés (application/timestamp-query et application/timestamp-reply)… ou pire, ils filtrent l’user-agent de l’appelant !
Notons aussi le non respect des normes de signtool qui encode en PEM et travaille en application/octect-stream….

Pour plus de souplesse, passez par GlobalSign ;) (http://www.globalsign.com/)


Un petit rappel sur la signature croisée pour les objets noyau de Windows : http://msdn.microsoft.com/windows/hardware/gg487315

Ce qui peut se résumer à :

signtool sign /v ^
/d "mimikatz driver 0.01 :-)" /du "http://blog.gentilkiwi.com/mimikatz" ^
/sha1 ab9e92b943ed47d915bc26939e24a58303acaa7e ^
/ac c:\security\mimikatz\tools\MSCV-GlobalSign.cer ^
/t http://timestamp.globalsign.com/scripts/timstamp.dll ^
c:\security\mimikatz\Win32\*.sys c:\security\mimikatz\driver\objfre_wnet_x86\i386\*.sys ^
c:\security\mimikatz\x64\*.sys c:\security\mimikatz\driver\objfre_wnet_amd64\amd64\*.sys

Cryptography API: Next Generation et export de clés privées (aperçu)

Un petit billet sur la gestion de l’export des clés privées par la CNG (Cryptography API: Next Generation)…

Petite introduction

Un peu de documentation sur ces API pour commencer :

Il est plus qu’aisé de sortir des clés privées « non exportables » gérées par la CryptoAPI, en effet celles-ci sont traitées directement dans la mémoire du processus appelant, et donc totalement à notre merci (JNZ qui deviennent JMP…).
Microsoft a fait un petit pas sur ce sujet, il a décidé d’isoler les clés privées dans le processus « sécurisé » lsass.exe, via le service KeyIso.

Bénéficier de la CNG

Il est malheureusement très difficile de bénéficier de cette avancée, en effet, lors de l’import d’un PFX ou d’un P12 il ne nous est pas proposé de sélectionner le nouveau provider KSP : « Microsoft Software Key Storage Provider », l’on se retrouve donc de manière automatique avec les providers par défaut de la CryptoAPI… quelle avancée !

Pour passer par la CNG l’on doit :

  • programmer (!)
  • utiliser un outil ayant fait ses preuves dans le domaine de la convivialité : certutil

Exemple d’import avec certutil :

  • Avec clé exportable : certutil -user -p waza -csp "Microsoft Software Key Storage Provider" -importpfx test.p12
  • Avec clé « non » exportable : certutil -user -p waza -csp "Microsoft Software Key Storage Provider" -importpfx test.p12 NoExport

Résultat, la CNG est tellement sécurisée, que notre MMC préférée (certmgr.msc) est, pour le moment, incapable d’exporter une clé exportable…

Notre seule solution :
certutil -user -p export_waza -privatekey -exportpfx test export_test.p12

Jouons avec lsass

Manipuler quelques octets dans lsass.exe n’est pas très compliqué :

mimikatz # crypto::patchcng
CNG@lsass patché !

mimikatz # crypto::exportCertificates
Emplacement : 'CERT_SYSTEM_STORE_CURRENT_USER'\My
         - test
                Container Clé : test-a9282d11-cbcb-4154-90f7-c94138850d63
                Provider      : Microsoft Software Key Storage Provider
                Exportabilité : NON
                Taille clé    : 2048
                Export privé dans  'CERT_SYSTEM_STORE_CURRENT_USER_My_0_test.pfx' : OK
                Export public dans 'CERT_SYSTEM_STORE_CURRENT_USER_My_0_test.der' : OK

Même certutil a l’air d’accord…

================ Certificat 0 ================
Numéro de série : 07
Émetteur: CN=test, C=FR
 NotBefore : 12/04/2011 02:10
 NotAfter : 11/04/2012 02:10
Objet: CN=test, C=FR
La signature correspond à la clé publique
Certificat racine : le sujet correspond à l’émetteur
Modèle:
Hach. cert. (sha1) : 68 61 30 0d 9a 8d 9a 85 e5 d6 9b 0d aa d2 b7 2e e3 67 09 0a
  Conteneur de clé = test-a9282d11-cbcb-4154-90f7-c94138850d63
  Fournisseur = Microsoft Software Key Storage Provider
La clé privée NE PEUT PAS être exportée
Succès du test de chiffrement
CertUtil: -exportPFX La commande s’est terminée correctement.

Inclus dans mimikatz (article : http://blog.gentilkiwi.com/mimikatz/crypto#patchcng)

Shhh…

…avec quelques adaptations, cela marche (pour le moment) avec Windows 8 build 7850…
(l’audit n’est pas encore implémenté)

CNG Export sous Windows 8 build 7850

Signature numérique XML, canonicalisation et commentaires

Parmi les différentes options de canonicalisation (c14n) disponibles lors de signature de documents XML, nous trouvons la possibilité de prendre en compte ou non les commentaires dans le calcul du hash…

Dans le cas d’une canonicalisation exclusive, les transformations possibles sont :

  • http://www.w3.org/2001/10/xml-exc-c14n#
  • http://www.w3.org/2001/10/xml-exc-c14n#WithComments

Mais y a-t-il une réelle différence dans le hash (donc dans la signature) ?

Un exemple de nœud XML référencé par l’ID « object » que nous voudrions signer :

<Object Id="object"><!--commentaire-->texte</Object>

… et soumettons-le à différentes transformations en vue d’une signature !

  • Canonicalisation exclusive, avec omission des commentaires (référence par Id) :

    Reference maReference = maSignatureFactory.newReference(
                    "#object",
                    maSignatureFactory.newDigestMethod(DigestMethod.SHA1, null),
                    Collections.singletonList(maSignatureFactory.newTransform(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null)),
                    "http://www.w3.org/2000/09/xmldsig#Object",
                    "data-object");

    2 – Référence par ID sur le noeud object
    4 – Méthode de canonicalisation exclusive avec omission des commentaires (CanonicalizationMethod.EXCLUSIVE)

    Résultat :

    <Reference Id="data-object" Type="http://www.w3.org/2000/09/xmldsig#Object" URI="#object">
    	<Transforms>
    		<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    	</Transforms>
    	<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    	<DigestValue>xVvVl8rEZss+SMzVbGBf+xjXRm4=</DigestValue>
    </Reference>

    1 – Référence par ID sur le noeud object
    3 – Méthode de canonicalisation exclusive avec omission des commentaires (http://www.w3.org/2001/10/xml-exc-c14n#)
    6 – Hash du noeud XML après canonicalisation : xVvVl8rEZss+SMzVbGBf+xjXRm4=

  • Canonicalisation exclusive, avec conservation des commentaires (référence par Id) :

    Reference maReference = maSignatureFactory.newReference(
                    "#object",
                    maSignatureFactory.newDigestMethod(DigestMethod.SHA1, null),
                    Collections.singletonList(maSignatureFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null)),
                    "http://www.w3.org/2000/09/xmldsig#Object",
                    "data-object");

    2 – Référence par ID sur le noeud object
    4 – Méthode de canonicalisation exclusive avec conservation des commentaires (CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS)

    Résultat :

    <Reference Id="data-object" Type="http://www.w3.org/2000/09/xmldsig#Object" URI="#object">
    	<Transforms>
    		<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
    	</Transforms>
    	<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    	<DigestValue>xVvVl8rEZss+SMzVbGBf+xjXRm4=</DigestValue>
    </Reference>

    1 – Référence par ID sur le noeud object
    3 – Méthode de canonicalisation exclusive avec conservation des commentaires (http://www.w3.org/2001/10/xml-exc-c14n#WithComments)
    6 – Hash du noeud XML après canonicalisation : xVvVl8rEZss+SMzVbGBf+xjXRm4=

Mais comment est-ce possible ? Dans le premier cas, nous indiquons explicitement une canonicalisation avec omission des commentaires et obtenons le hash : xVvVl8rEZss+SMzVbGBf+xjXRm4=
Puis indiquons une canonicalisation avec conservation des commentaires et obtenons le même hash !

Explications :

Ce comportement vient de petites spécificités de nos amis du W3C… : http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel :

When a fragment is not preceded by a URI in the URI-Reference, XML Signature applications MUST support the null URI and shortname XPointer [XPointer-Framework]. We RECOMMEND support for the same-document XPointers ‘#xpointer(/)’ and ‘#xpointer(id(‘ID’))’ if the application also intends to support any canonicalization that preserves comments. (Otherwise URI= »#foo » will automatically remove comments before the canonicalization can even be invoked due to the processing defined in Same-Document URI-References (section 4.3.3.3).) All other support for XPointers is OPTIONAL, especially all support for shortname and other XPointers in external resources since the application may not have control over how the fragment is generated (leading to interoperability problems and validation failures).

Les commentaires seraient ainsi enlevés avant même le processus de canonicalisation de part la méthode de sélection du nœud cible (par référence directe à l’Id), cette lecture est confirmée par un des paragraphes suivants :

URI= »#chapter1″
Identifies a node-set containing the element with ID attribute value ‘chapter1’ of the XML resource containing the signature. XML Signature (and its applications) modify this node-set to include the element plus all descendants including namespaces and attributes — but not comments.

Ainsi, nous devrions pouvoir nous en sortir avec une référence par XPointer sur un Id plutôt qu’une référence directe sur un Id…

  • Canonicalisation exclusive, avec omission des commentaires (référence par XPointer sur Id)) :

    Reference maReference = maSignatureFactory.newReference(
                    "#xpointer(id('object'))",
                    maSignatureFactory.newDigestMethod(DigestMethod.SHA1, null),
                    Collections.singletonList(maSignatureFactory.newTransform(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null)),
                    "http://www.w3.org/2000/09/xmldsig#Object",
                    "data-object");

    2 – Référence par XPointer sur ID sur le noeud object
    4 – Méthode de canonicalisation exclusive avec omission des commentaires (CanonicalizationMethod.EXCLUSIVE)

    Résultat :

    <Reference Id="data-object" Type="http://www.w3.org/2000/09/xmldsig#Object" URI="#xpointer(id('object'))">
    	<Transforms>
    		<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    	</Transforms>
    	<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    	<DigestValue>xVvVl8rEZss+SMzVbGBf+xjXRm4=</DigestValue>
    </Reference>

    1 – Référence par XPointer ID sur le noeud object
    3 – Méthode de canonicalisation exclusive avec omission des commentaires (http://www.w3.org/2001/10/xml-exc-c14n#)
    6 – Hash du noeud XML après canonicalisation : xVvVl8rEZss+SMzVbGBf+xjXRm4= (le même que précédemment, heureusement ;))

  • Canonicalisation exclusive, avec conservation des commentaires (référence par XPointer sur Id) :

    Reference maReference = maSignatureFactory.newReference(
                   "#xpointer(id('object'))",
                    maSignatureFactory.newDigestMethod(DigestMethod.SHA1, null),
                    Collections.singletonList(maSignatureFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null)),
                    "http://www.w3.org/2000/09/xmldsig#Object",
                    "data-object");

    2 – Référence par XPointer sur ID sur le noeud object
    4 – Méthode de canonicalisation exclusive avec conservation des commentaires (CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS)

    Résultat :

    <Reference Id="data-object" Type="http://www.w3.org/2000/09/xmldsig#Object" URI="#xpointer(id('object'))">
    	<Transforms>
    		<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
    	</Transforms>
    	<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
    	<DigestValue>vHnUzn+afpzilGODV/4utR5xIlQ=</DigestValue>
    </Reference>

    1 – Référence par XPointer sur ID sur le noeud object
    3 – Méthode de canonicalisation exclusive avec conservation des commentaires (http://www.w3.org/2001/10/xml-exc-c14n#WithComments)
    6 – Hash du noeud XML après canonicalisation : vHnUzn+afpzilGODV/4utR5xIlQ=

Cette fois-ci le « bon » hash !!!

Conclusions et remarques :

Dans tous les cas précédents, les hashs et signatures engendrés seront heureusement corrects, mais certaines incompréhensions peuvent découler de l’utilisation des références par Id lors de canonicalisation avec conservation des commentaires… Un document dans lequel nous aurions modifié les commentaires de manière insultante ou publicitaire garderait une signature correcte malgré l’utilisation explicite de canonicalisation avec conservation des commentaires.

L’utilisation de référence par XPointer explicite, dont le support est déjà recommandé par le W3C pour les signatures XMLDSIG, est donc un bon choix.
Malheureusement ce type de référence n’est pas forcément encore supporté par tous les logiciels de signature ou de vérification de signature.

Références :

Bizarreries LDAPS Windows 2000 et OpenSSL :/

Un cas « rigolo » d’utilisation d’OpenSSL en client SSL (s_client) qui change de comportement selon l’activation du mode debug ou non… :

Sans mode -debug :(

openssl s_client -connect xxx.local:636 -CAfile ssl\ac_root.pem -showcerts -msg -state

Résultat :

CONNECTED(00000754)
SSL_connect:before/connect initialization
>>> TLS 1.0 Handshake [length 00cd], ClientHello
SSL_connect:SSLv2/v3 write client hello A
<<< TLS 1.0 Handshake [length 004a], ServerHello
SSL_connect:SSLv3 read server hello A
<<< TLS 1.0 Handshake [length 0b4a], Certificate
depth=2 O = XXX, C = FR
verify return:1
depth=1 O = XXX, C = FR
verify return:1
depth=0 C = FR, O = XXX, CN = XXX
verify return:1
SSL_connect:SSLv3 read server certificate A
<<< TLS 1.0 Handshake [length 0971], CertificateRequest
SSL_connect:SSLv3 read server certificate request A
<<< TLS 1.0 Handshake [length 0004], ServerHelloDone
SSL_connect:SSLv3 read server done A
>>> TLS 1.0 Handshake [length 0007], Certificate
SSL_connect:SSLv3 write client certificate A
>>> TLS 1.0 Handshake [length 0106], ClientKeyExchange
SSL_connect:SSLv3 write client key exchange A
>>> TLS 1.0 ChangeCipherSpec [length 0001]
SSL_connect:SSLv3 write change cipher spec A
>>> TLS 1.0 Handshake [length 0010], Finished
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL_connect:failed in SSLv3 read finished A
2052:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:.\ssl\s23_lib.c:177:

Une petite capture réseau :
windows_2000_ldaps_2048_nodebug_ko
(1 packet pour les handshakes de fin)

Avec mode -debug :)

openssl s_client -connect xxx.local:636 -CAfile ssl\ac_root.pem -showcerts -msg -state -debug

Résultat :

CONNECTED(00000754)
SSL_connect:before/connect initialization
write to 0xaa4918 [0xaa8f00] (210 bytes => 210 (0xD2))
>>> TLS 1.0 Handshake [length 00cd], ClientHello
SSL_connect:SSLv2/v3 write client hello A
read from 0xaa4918 [0xaae460] (7 bytes => 7 (0x7))
read from 0xaa4918 [0xaae46a] (5383 bytes => 5383 (0x1507))
<<< TLS 1.0 Handshake [length 004a], ServerHello
SSL_connect:SSLv3 read server hello A
<<< TLS 1.0 Handshake [length 0b4a], Certificate
depth=2 O = XXX, C = FR
verify return:1
depth=1 O = XXX, C = FR
verify return:1
depth=0 C = FR, O = XXX, CN = XXX
verify return:1
SSL_connect:SSLv3 read server certificate A
<<< TLS 1.0 Handshake [length 0971], CertificateRequest
SSL_connect:SSLv3 read server certificate request A
<<< TLS 1.0 Handshake [length 0004], ServerHelloDone
SSL_connect:SSLv3 read server done A
>>> TLS 1.0 Handshake [length 0007], Certificate
write to 0xaa4918 [0xab6e68] (12 bytes => 12 (0xC))
SSL_connect:SSLv3 write client certificate A
>>> TLS 1.0 Handshake [length 0106], ClientKeyExchange
write to 0xaa4918 [0xab6e68] (267 bytes => 267 (0x10B))
SSL_connect:SSLv3 write client key exchange A
>>> TLS 1.0 ChangeCipherSpec [length 0001]
write to 0xaa4918 [0xab6e68] (6 bytes => 6 (0x6))
SSL_connect:SSLv3 write change cipher spec A
>>> TLS 1.0 Handshake [length 0010], Finished
write to 0xaa4918 [0xab6e68] (37 bytes => 37 (0x25))
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
read from 0xaa4918 [0xaae463] (5 bytes => 5 (0x5))
read from 0xaa4918 [0xaae468] (1 bytes => 1 (0x1))
<<< TLS 1.0 ChangeCipherSpec [length 0001]
read from 0xaa4918 [0xaae463] (5 bytes => 5 (0x5))
read from 0xaa4918 [0xaae468] (32 bytes => 32 (0x20))
<<< TLS 1.0 Handshake [length 0010], Finished
SSL_connect:SSLv3 read finished A

Une petite capture réseau :
windows_2000_ldaps_2048_debug_ok
(2 packets pour les handshakes de fin)

Résultats :

OpenSSL : mauvais point ! Les packets envoyés par OpenSSL en mode debug ne sont pas ordonnancés de la même manière qu’en mode « normal » !!!
Windows 2000 : TRES mauvais point, les certificats en 1024 bits fonctionnent quelque soit le mode de trace d’OpenSSL, contrairement à ceux en 2048 bits
Windows 2003 fonctionne, lui, normalement.

Pour le moment : Juniper / OpenSSL : 1 ; Windows 2000 : 0