2014-10-03 2 views
2

Я пытаюсь проверить цифровую подпись XML с помощью openSSL. Когда я фактически использую EVP_VerifyFinal, я получаю код ошибки 0D07209B (ASN1_get_object: слишком длинный). Он, как я загружаю в KeyInfo от CERT:Как загрузить ключ DSA из KeyInfo с помощью openSSL

<KeyInfo> 
<KeyValue> 
    <DSAKeyValue> 
    <P>/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFw==</P> 
    <Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</Q> 
    <G>Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA==</G> 
    <Y>butK4tBy8dwSJFjTRpTvmYZYnsDGO4CzMVgcD8EQ2UJrQZd0ZapQI/Ea2DZzQBTFjjdnNkFuNOtjVI615lhiBQ==</Y> 
    </DSAKeyValue> 
</KeyValue> 
</KeyInfo> 

Мой (псевдокод) метод для загрузки РПОО:

pDSA = DSA_new(); 
pDSA.p = BN_bin2bn(base64Decode(text of P element)); 
pDSA.q = BN_bin2bn(base64Decode(text of Q element)); 
pDSA.g = BN_bin2bn(base64Decode(text of G element)); 
pDSA.pub_key = BN_bin2bn(base64Decode(text of Y element)); 

Использование BN_bn2hex после этого дает мне значения:

p: FCA682CE8E12CABA26EFCCF7110E526DB078B05EDECBCD1EB4A208F3AE1617AE01F35B91A47E6DF63413C5E12ED0899BCD132ACD50D99151BDC43EE737592E17 
q: 962EDDCC369CBA8EBB260EE6B6A126D9346E38C5 
g: 678471B27A9CF44EE91A49C5147DB1A9AAF244F05A434D6486931D2D14271B9E35030B71FD73DA179069B32E2935630E1C2062354D0DA20A6C416E50BE794CA4 
pub_key: 6EEB4AE2D072F1DC122458D34694EF9986589EC0C63B80B331581C0FC110D9426B41977465AA5023F11AD836734014C58E376736416E34EB63548EB5E6586205 

, подтверждающие подпись:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <SignedInfo> 
     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/> 
     <Reference URI=""> 
     <Transforms> 
     <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
     </Transforms> 
     <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>  
     <DigestValue>uooqbWYa5VCqcJCbuymBKqm17vY=</DigestValue> 
     </Reference> 
    </SignedInfo>  
    <SignatureValue>L4h4TFDj5rDKCHm0D+aH2LeSfAMV2t0V5S91Afu6U0NlfpjxdTXRUA==</SignatureValue> 
    <KeyInfo> 
    <KeyValue> 
     <DSAKeyValue>   
     <P>/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFw=</P> 
     <Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</Q> 
     <G>Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA==</G> 
     <Y>POKkQtGuazaz6OEWi91P4C9z1tREpeP9f7L3piRD/3TiNFzvt0BmYzNO0CoPSjEVTXYKIRo/+HXK6MhBRk2eUw=</Y> 
    </DSAKeyValue> 
    </KeyValue> 
    </KeyInfo> 
    </Signature> 
</Envelope> 

Вот как я проверить подпись:

pkey = EVP_PKEY_new; 
    EVP_PKEY_set1_DSA(pkey, pdsa) 
    EVP_MD_CTX_init(ctx); 
    EVP_VerifyInit(@ctx, EVP_sha1) 
    EVP_VerifyUpdate(@ctx, digest of SignedInfo); 
    bytes = unbase64(text of SignatureValue) 
    EVP_VerifyFinal(@ctx, btes, length(bytes)}, pKey); 

Verify окончательные возвращает следующие ошибки:

0D07207B:asn1 encoding routines:ASN1_get_object:header too long) 
0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header) 
0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error) 

Так как я загрузке сертификата или значение подписи Неправильно. Согласно спецификации, значение подписи «Значение подписи состоит из кодировки base64 конкатенации двух октетных потоков, которые соответственно являются результатом октетного кодирования значений r и s в этом порядке» - но я не могу найти нигде в документацию openSSL, которая должна быть передана EVP_VerifyInit для значения подписи для DSA-подписи. Я нашел одну ссылку в архиве электронной почты, которая указывала на RFC 3279, который, как мне кажется, указывает тот же формат (Dss-Sig-Value :: = SEQUENCE {r INTEGER, s INTEGER}

ответ

1

Да, вы уже ответили на свой вопрос. Вы должны разделить полученную подпись на два (два 20 байтовых значения, как указано в XML-DSig), а затем создать подпись ASN.1. Это действительно будет состоять из следующего ASN.1 МЭД структуру:.

Dss-Sig-Value ::= SEQUENCE { 
    r INTEGER, 
    s INTEGER 
} 

МЭД является «метка, длина, значение» структура Теперь последовательность имеет кодировку тегов 30, то длину МЭД двух закодированных целые числа, а г и s являются целыми числами ва lues, закодированный с тегом 02, затем длина, за которой следует кратчайшее представление подписанного большого целочисленного числа endian.

Как программирование ASN.1 в лучшем случае сложнее и совершенно уязвимо, как наихудшее (все версии до 1.0.1 из OpenSSL была ошибка с повреждением памяти, проверка подлинности Windows NT старых была полностью разрушена) я покажу, как создать эту структуру, используя псевдо-код:

  • конвертировать base64 в байтах (без знака символов, сорок из них)
  • использовать первые 20 байт для rData, второй для sData (или лучше, разделить пополам)
  • полосы все ведущие (крайний левый) 00 оцененные байты rData и sData
  • , если ведущий байт находится 80 или над , пр. EFix в 00 байт в rDatasData
  • создать структуру 30 LL { 02 LL { rData } 02 LL { sData } } где LL имеет размер в байтах структуры между скобками

Я оставлю вас, чтобы выполнять кодирование. Обратите внимание, что это будет работать до тех пор, пока LL никогда не будет иметь значение 128 или более (что должно быть в случае DSA).

Возможно, вы захотите переключиться на ECDSA; обратите внимание, что это, вероятно, потребует такой же структуры выше. Также обратите внимание, что я не вижу, правильно ли введен ввод дайджеста, но он должен хотя бы разрешить ошибку ASN.1.


В конце концов, вы должны получить this structure для вас текущей подписи (обратите внимание, что это один немного скучный, поскольку он не содержит каких-либо начальных значений 00 и не содержит каких-либо начальных байтов, равные или более высокие чем 128).

+0

Это действительно здорово, спасибо. Я не мог найти, какую кодировку asn.1 я должен использовать, и я действительно ценю, что вы делаете для этого работу. Теперь я могу проверить подпись. Однако у меня есть один следующий вопрос: когда я подписываюсь, используя EVP_MD_CTX_init (ctx), EVP_SignInit (ctx, EVP_sha256), EVP_SignUpdate (@ctx, байты дайджеста), EVP_SignFinal (ctx, sig, len, pKey), я получаю len из 70, который представляет собой структуру asn.1, которая содержит 2 32 байтовых ключа, а не 20 байтовых ключей. Но они должны быть только 20 байтов? –

+0

Возможно, зависит от используемого ключа. 20 байт относится к значению 160 бит для параметра q. Теперь вы, вероятно, используете ключ из 2048/256 бит. В течение долгого времени использовались только DSA-ключи с размерами 1024/160 бит, и спецификация XML, похоже, все еще живет в те времена :) –

+0

отлично, спасибо, я очень ценю это –

Смежные вопросы