4

Java Framework から openssl 証明書を管理するときに問題が発生しています。

openssl x509 -subject_hash ...

出力は、Java フレームワークが を呼び出したときに返すものとは異なりX509_NAME_hash()ます。以下を参照してください。

これは、openssl が SHA1 の計算方法を変更したためです。現在、MD5 の場合のようにサブジェクトの ASN.1 DER 表現に基づいてハッシュを作成する代わりに、まず CANONICAL 表現を計算し、次にそれに基づいて ASN.1 DER を計算し、それをSHA1 アルゴリズムの入力。

NativeCrypto.java :

// --- X509_NAME -----------------------------------------------------------
public static int X509_NAME_hash(X500Principal principal) {
    return X509_NAME_hash(principal, "SHA1");
}

private static int X509_NAME_hash(X500Principal principal, String algorithm) {
    try {
        byte[] digest = MessageDigest.getInstance(algorithm).digest(principal.getEncoded());
        return Memory.peekInt(digest, 0, ByteOrder.LITTLE_ENDIAN);
    } catch (NoSuchAlgorithmException e) {
        throw new AssertionError(e);
    }
}

Javaの下層でそれを修正しようとするために、opensslライブラリをx_name.c調べていました。x509_cmp.cしかし、私は成功しませんでした。

X509_NAME_hashのメソッドを変更する必要があることを理解していx509_cmp.cます。しかし、その変更が直前か直後かはわかりませんi2d_X509_NAME(x,NULL); 。このメソッドは、サブジェクト名のCANONICAL表現を計算していますよね? 次に、その出力に基づいて ASN1 DER を計算する必要がありますよね? しかし、私はそれを作ることができません。

この問題を解決するために、誰かが私を案内したり、これについて何らかの光を当てたりしていただければ幸いです。

x509_cmp.c :

    unsigned long X509_NAME_hash(X509_NAME *x)
    {
    unsigned long ret=0;
    unsigned char md[SHA_DIGEST_LENGTH];

    /* Make sure X509_NAME structure contains valid cached encoding */
    i2d_X509_NAME(x,NULL);
    if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(),
            NULL))
            return 0;

    ret=(   ((unsigned long)md[0]     )|((unsigned long)md[1]<<8L)|
            ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
            )&0xffffffffL;
    return(ret);
    }

この関数x509_name_canonは明らかに再エンコードを実行します。これは次のcrypto/asn1/x_name.cとおりです。

/* This function generates the canonical encoding of the Name structure.
 * In it all strings are converted to UTF8, leading, trailing and
 * multiple spaces collapsed, converted to lower case and the leading
 * SEQUENCE header removed.
 * 
 */
4

1 に答える 1

1

OpenSSL の新しい SubjectHash と同じ結果が必要な場合は、DN の先頭のシーケンスを削除する必要があります。したがって、次のようなことをしなければなりません:

// --- X509_NAME -----------------------------------------------------------

public static int X509_NAME_hash(X500Principal principal) {
    return X509_NAME_hash(principal, "SHA1");
}

private static int X509_NAME_hash(X500Principal principal, String algorithm) {
    try {

        byte[] princ = principal.getEncoded();
        final ASN1Sequence obj = (ASN1Sequence) ASN1Object.fromByteArray( princ );

        // Remove the leading sequence ...
        final DERSet enc = (DERSet) obj.getObjectAt(0);
        final byte[] toHash = enc.getDEREncoded();

        MessageDigest md = MessageDigest.getInstance(algorithm);
        byte[] digest = md.digest(toHash);
        return Memory.peekInt(digest, 0, ByteOrder.LITTLE_ENDIAN);

    } catch (NoSuchAlgorithmException e) {
        throw new AssertionError(e);
    } catch (IOException e) {
        throw new AssertionError(e);
    }
}

これで、結果は OpenSSL の新しい Subject_hash と同じになります。

于 2013-11-14T07:42:53.327 に答える