Почему мой ключевой идентификатор не совпадает? - PullRequest
7 голосов
/ 29 июня 2011

Я пытаюсь расшифровать электронную почту S / MIME (первоначально отправленную через Outlook), и для этого я использую API bouncycastle.Однако я сталкиваюсь с проблемой.

В хранилище сертификатов Windows у меня есть сертификат для получателя.Ранее я использовал его для отправки подписанного и зашифрованного электронного письма другой стороне, а они, в свою очередь, использовали его для отправки мне зашифрованного ответа.Затем я экспортировал сертификат (с закрытым ключом) в виде файла .pfx и загрузил этот файл pfx в хранилище ключей Java.Однако это не работает, и я подозреваю, что это потому, что идентификаторы ключа субъекта не совпадают.

Вот код, который я использую для получения идентификатора ключа субъекта из хранилища ключей:

KeyStore ks = KeyStore.getInstance("PKCS12");
char[]   pw = "password".toCharArray();

ks.load(new FileInputStream("d:\\cert_priv_key.pfx"), pw);

Enumeration en = ks.aliases();

while( en.hasMoreElements() )
{
    String alias = (String)en.nextElement();
    System.out.println(alias);

    if( ks.isKeyEntry(alias) )
    {
        Certificate[]   chain = ks.getCertificateChain(alias);
        X509Certificate cert  = (X509Certificate)chain[0];

        byte[] id = cert.getExtensionValue("2.5.29.14");

        System.out.println("  " + toHex(id));
    }
}

Это распечатывает следующий идентификатор ключа:

04 16 04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3

Однако, когда я проверяю хранилище сертификатов Windows, идентификатор ключа отличается:

88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3

KeyStore возвращаетдополнительные 4 байта впереди (идентификатор ключа субъекта должен быть 160-битным SHA1-хэшем ключа и, следовательно, длиной 20 байтов, правильно?).

Еще более запутанным является тот факт, что когда я анализируюS / MIME электронная почта, используя API bouncycastle, и просмотрите получателей (SMIMEEnveloped.getRecipientInfos().getRecipients()), единственный возвращенный получатель (должен быть только один) имеет этот идентификатор ключа субъекта:

04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3

... itимеет только два дополнительных байта, а не четыре, и я предполагаю, что именно поэтому я не могу расшифровать письмо с сертификатом.

Почему ни один из этих идентификаторов ключей субъекта не совпадает?Что я делаю не так?

Ответы [ 3 ]

16 голосов
/ 30 июня 2011

Все эти ответы последовательны, если вы понимаете все спецификации, но, конечно, это означает, что они сбивают с толку, если вы не понимаете. Первое место для поиска - RFC 5280, раздел 4.2.1.2 . В этом случае используется метод (1). Затем посмотрите в разделе A.2 определение KeyIdentifier. Он определяется как ОКТЕТНАЯ СТРОКА. Теперь посмотрим, как кодировать строку ONET ASN.1 . Он должен начинаться с шестнадцатеричного 04, за которым следует длина в байтах (20 байтов или 14 шестнадцатеричных), за которой следует фактическая строка октетов (хеш SHA1). Таким образом, содержимое расширения должно быть

04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3

Наконец, посмотрите на определение ASN.1 Extension . Это говорит о том, что значение расширения должно быть закодировано как OCTET STRING. В случае этого конкретного расширения, чистый эффект заключается в том, что он кодируется дважды подряд как OCTET STRING. На этом уровне OCTET STRING - это предыдущая OCTET STRING, которая включает два байта заголовка 04 14, поэтому длина равна шестнадцатеричной 16, а кодировка -

.
04 16 04 14 88 ed bb 7c 64 7b 41 63 48 0a 24 40 2b 3c d0 78 72 3c 30 b3

Это значение, возвращаемое методом X509Extension.getExtensionValue () . Теперь интересная часть идентификатора ключа - это просто хэш SHA1, который начинается с 88, так что это то, что показывает утилита Windows. Очевидно, что метод bouncycastle, который вы используете, отображает расширение без дополнительного декодирования.

1 голос
/ 30 июня 2011

Сообщение S / MIME создано Outlook 2010?

, если это так, см. http://bouncy -castle.1462172.n4.nabble.com / Re-ReadEncryptedMail-sample-and-SubjectKeyIdentifier-вместо-IssuerSerial-Outlook-2010-Hack-td3042968.html и https://bugzilla.mozilla.org/show_bug.cgi?id=559243 для получения дополнительной информации

Martijn Brinkers

0 голосов
/ 29 апреля 2015

Принятый ответ от GregS мне очень помог.

Код, который работал для меня:

X509Certificate certificate = ...
byte[] encExtensionSubjectKeyIdentifier = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId());

// Unwrap first 'layer'
ASN1Primitive skiPrimitive = JcaX509ExtensionUtils.parseExtensionValue(encExtensionSubjectKeyIdentifier);

// Unwrap second 'layer'
byte[] keyIdentifier = ASN1OctetString.getInstance(skiPrimitive.getEncoded()).getOctets();

// Use keyIdentifier in e.g. CMS SignerInfo
SignerInfoGenerator signerInfoGenerator = jcaSignerInfoGeneratorBuilder.build(sha1Signer, keyIdentifier);
...