5

ファイルから公開鍵を復元したい。動作するJavaコードは次のとおりです。

PublicKey readPubKeyFromFile(AssetFileDescriptor cle) throws IOException {
    // read RSA public key
    byte[] encodedKey = new byte[(int) cle.getDeclaredLength()];
    cle.createInputStream().read(encodedKey);

    // create public key
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
    PublicKey pk = null;
    try {
        KeyFactory kf = KeyFactory.getInstance("RSA");
        pk = kf.generatePublic(publicKeySpec);
    } catch(Exception e) {
        Logger.getInstance().logError("KeyUtils", e.toString());
    }
    return pk;
}

そして、動作しない iOS コードは次のとおりです。

-(SecKeyRef)readPublicKeyFromFile:(NSString*)filename andExtension:(NSString*)extension {

NSString*   filePath = [[NSBundle mainBundle] pathForResource:filename ofType:extension];
NSData*     encodedKey = [NSData dataWithContentsOfFile:filePath];

CFDataRef myCertData = (CFDataRef)encodedKey;

SecCertificateRef cert = SecCertificateCreateWithData (kCFAllocatorSystemDefault, myCertData);
CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **) &cert, 1, NULL);
SecPolicyRef policy = SecPolicyCreateBasicX509();

SecTrustRef trust;

OSStatus check =  SecTrustCreateWithCertificates(certs, policy, &trust);

if (check != noErr)
{
    NSLog(@"Problem extracting public key from file: %@", filename);
    return nil;
}

SecTrustResultType trustResult;
SecTrustEvaluate(trust, &trustResult);
SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust);

return pub_key_leaf;
}

私のiOSコードで何が間違っているのか考えていますか?

4

1 に答える 1

1

私はあなたのコードをテストしましたが、何も問題はありません。この問題は、公開鍵を取得しようとしている証明書の形式に関連しているようです。

関数 SecCertificateCreateWithData() は、提供する証明書が DER 形式であることを前提としています。見つけたほとんどの証明書は、有名な .pem 形式のように base64 でエンコードされています。正しい形式の DER 証明書 (openssl を使用して DER に変換された developer.apple.com の証明書フォーム) を使用してコードをテストしたところ、公開キーが正しく抽出されました。

.pem 証明書を DER に変換するには、ターミナルで openssl を使用するだけです。

openssl x509 -in developer.apple.com.pem  -outform der -out cert.der

その後、出力された証明書ファイルはコードで問題なく動作するはずです。

ただし、アプリケーション自体で証明書を変換できます。x509 base64 でエンコードされた証明書 (.pem でエンコードされた証明書を使用していると仮定) を取得してバイナリに変換するだけで済みます。

あなたがそれを行う方法の例があります:

このコードは、証明書が次の標準でエンコードされていることを前提としています。

-----BEGIN CERTIFICATE-----
< your base64 encoded certificate goes here >
-----END CERTIFICATE-----

この証明書をバイナリ DER に変換するコードは次のとおりです。

-(NSData *)getBinaryCertificateFromPemEncodedFile:(NSString *)filename andExtension:(NSString *)extension
{
    NSString* filePath = [[NSBundle mainBundle] pathForResource:filename ofType:extension];
    NSString *pemCert = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    //The header and footer conforms to .pem specificatio
    NSString *header = @"-----BEGIN CERTIFICATE-----";
    NSString *footer = @"-----END CERTIFICATE-----";

    NSString *base64Cert;
    NSScanner *scanner = [NSScanner scannerWithString:pemCert];
    //First we ignore the header part
    [scanner scanString:header intoString:nil];
    //Then we copy the base64 string excluding the footer
    [scanner scanUpToString:footer intoString:&base64Cert];

    //The reason I'm using NSDataBase64DecodingIgnoreUnknownCharacters is to exclude possible line breaks in the encoding
    NSData *binaryCertificate = [[NSData alloc] initWithBase64EncodedString:base64Cert options:NSDataBase64DecodingIgnoreUnknownCharacters];

    return binaryCertificate;
}

次に、完全に機能するコードを少し調整すると、うまくいきます。

-(SecKeyRef)readPublicKeyFromCertificate:(NSData *)binaryCertificate {

    NSData *encodedKey = binaryCertificate;

    CFDataRef myCertData = (CFDataRef)CFBridgingRetain(encodedKey);

    SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorSystemDefault, myCertData);
    SecPolicyRef policy = SecPolicyCreateBasicX509();

    SecTrustRef trust;
    //If you only have one certificate you don't need to put it inside an array
    OSStatus check =  SecTrustCreateWithCertificates(cert, policy, &trust);

    if (check != noErr)
    {
        NSLog(@"Problem extracting public key from certificate");
        return nil;
    }

    SecTrustResultType trustResult;
    SecTrustEvaluate(trust, &trustResult);
    SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust);

    return pub_key_leaf;
}

次に、それを呼び出します:

NSData *data = [self getBinaryCertificateFromPemEncodedFile:@"developer" andExtension:@"pem"];
SecKeyRef key = [self readPublicKeyFromCertificate:data];
NSLog(@"%@", key);

証明書が「有効」である場合は、次のように表示されます。

2014-09-15 21:52:13.275 cert[15813:60b] <SecKeyRef algorithm id: 1,
key type: RSAPublicKey, version: 2, block size: 2048 bits, exponent: {hex: 10001, decimal: 65537},
modulus: BE19E30F47F2D31F27D576CF007B3E615F986D14AFD0D52B825E01E90BA3E1CBB6F3A472E6AECDC28BC13D0B6E58FC497ACF61D80F274E4799602DA4F819E54ADDE2FBFA89FC4EB2172501DDED8DE0FBDDBC5550CC018C73E1FD8152C905DE850862B8D57596025DE1908D8337E95637AF0F52C4A11DA178FF737DCE09471BC0A49DAD7DB39F1BA1B693D3A12F9CA50EF388B50292C73076BF1EEE412A5CFA940E99D4CF07F17FAC87F0D0E2FC8FA3ACDDEEFCCE8AFEC407B94536FCB1E4ACF34773728D189F85EAE4347E0BF868D25C7CE89F8A29B4E6865C68F4F915DFA540549EE9333007145D367FE2852622AAD776F3E5D505A02E5155CC8646A01C1031,
addr: 0x9a48200>

テストでは、developer.apple.com の証明書を使用しました。ログで公開キーを確認して比較できます。

于 2014-09-15T21:03:53.093 に答える