Fingerprint von PublicKey

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

Macoun 2019 - Frühbucherrabatt endet morgen

  • Fingerprint von PublicKey

    Hi,

    ich möchte den FingerPrint (sha256) des PublicKeys eines Server-Zertifikats errechnen. Aber irgendwie bekomme ich es nicht hin, da sich der errechnete FingerPrint immer vom richtigen Fingerprint unterscheidet, gehe ich davon aus, dass ich die Daten scheinbar falsch aus der SecKeyRef ziehe.
    Hat jemand eine Idee wie ich einen sha256 hash von einem PublicKey (SecKeyRef) errechne?


    Viele Grüße
    mike
  • Mac & i Test Abo
  • Google bzw. Stack Overflow spuckt z.B. diesen Code aus:

    Quellcode

    1. + (NSData *)doSha256:(NSData *)dataIn {
    2. NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
    3. CC_SHA256(dataIn.bytes, dataIn.length, macOut.mutableBytes);
    4. return macOut;
    5. }

    Quellcode

    1. func sha256Hex(string: String) -> String? {
    2. guard let messageData = string.data(using:String.Encoding.utf8) else { return nil }
    3. var digestData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
    4. _ = digestData.withUnsafeMutableBytes {digestBytes in
    5. messageData.withUnsafeBytes {messageBytes in
    6. CC_SHA256(messageBytes, CC_LONG(messageData.count), digestBytes)
    7. }
    8. }
    9. return digestData.map { String(format: "%02hhx", $0) }.joined()
    10. }
    Alles anzeigen
  • Hi MCDan,

    vielen Dank! Allerdings beantwortet mir das nicht meine Frage, denn wie ich generell einen sha256 Hash errechne ist mir bekannt. Es ist mir nicht bekannt, wie ich den Hash vom PublicKey errechne. Ich hatte den PublicKey in NSData "konvertiert" und mir den Hash errechnet, doch allerdings ist der Hash unterschiedlich dem, den ich von OpenSSL erhalte oder dem den ich bei Android errechne.

    Hintergrund ist der, dass ich Public Key Pinning implementieren möchte und das nur mit Boardmitteln, das heißt auch ohne AFNetworking. Ich möchte einfach den Fingerprint der Public Keys hinterlegen und diesen dann mit dem Fingerprint des Public Keys des Server Zertifikates vergleichen.

    Viele Grüße

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von mike09 ()

  • MCDan schrieb:

    Wenn Du den Hash auch bei Android berechnest, dann hast Du den Algorithmus dafür doch, oder?
    Der Algorithmus ist ja nicht direkt das Problem. Ich zitiere einfach mal den Satz aus dem ersten Post.

    mike09 schrieb:

    Aber irgendwie bekomme ich es nicht hin, da sich der errechnete FingerPrint immer vom richtigen Fingerprint unterscheidet, gehe ich davon aus, dass ich die Daten scheinbar falsch aus der SecKeyRef ziehe.


    MyMattes schrieb:

    mike09 schrieb:

    Ich hatte den PublicKey in NSData "konvertiert" und mir den Hash errechnet,
    Ich würde mal schauen, ob auf dem Weg PublicKey zu NSData irgendein Encoding stattfindet, so dass im NSData nicht wirklich das steht, was Du erwartest...
    Mattes
    Das ist der Code den ich verwende. Ehrlich gesagt wüsste ich nicht, welches Encoding auf raw bytes angewendet werden soll.

    C-Quellcode

    1. - (NSData *)getPublicKeyBitsFromKey:(SecKeyRef)givenKey {
    2. static const uint8_t publicKeyIdentifier[] = "com.your.company.publickey";
    3. NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
    4. OSStatus sanityCheck = noErr;
    5. NSData * publicKeyBits = nil;
    6. NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
    7. [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    8. [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    9. [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    10. // Temporarily add key to the Keychain, return as data:
    11. NSMutableDictionary * attributes = [queryPublicKey mutableCopy];
    12. [attributes setObject:(__bridge id)givenKey forKey:(__bridge id)kSecValueRef];
    13. [attributes setObject:@YES forKey:(__bridge id)kSecReturnData];
    14. CFTypeRef result;
    15. sanityCheck = SecItemAdd((__bridge CFDictionaryRef) attributes, &result);
    16. if (sanityCheck == errSecSuccess) {
    17. publicKeyBits = CFBridgingRelease(result);
    18. // Remove from Keychain again:
    19. (void)SecItemDelete((__bridge CFDictionaryRef) queryPublicKey);
    20. }
    21. return publicKeyBits;
    22. }
    Alles anzeigen
    Viele Grüße
  • Sollte nicht:

    Quellcode

    1. SecKeyRef key = <# a key #>;
    2. CFErrorRef error = NULL;
    3. NSData* keyData = (NSData*)CFBridgingRelease( // ARC takes ownership
    4. SecKeyCopyExternalRepresentation(key, &error)
    5. );
    6. if (!keyData) {
    7. NSError *err = CFBridgingRelease(error); // ARC takes ownership
    8. // Handle the error. . .
    9. }
    ausreichen, um von einer SecKeyRef die NSData Representation zu erhalten?
  • MCDan schrieb:

    Sollte nicht:

    Quellcode

    1. SecKeyRef key = <# a key #>;
    2. CFErrorRef error = NULL;
    3. NSData* keyData = (NSData*)CFBridgingRelease( // ARC takes ownership
    4. SecKeyCopyExternalRepresentation(key, &error)
    5. );
    6. if (!keyData) {
    7. NSError *err = CFBridgingRelease(error); // ARC takes ownership
    8. // Handle the error. . .
    9. }


    ausreichen, um von einer SecKeyRef die NSData Representation zu erhalten?
    Das ist richtig. Nachdem ich so lange getestet hatte, hatte ich es mal geändert und habe den oberen Code weiter genutzt. Den kann ich aber wieder ändern.

    Aber dennoch ist der Hash (Base64 enkodiert) nicht gleich dem Hash den ich mit

    Shell-Script

    1. #!/bin/bash
    2. certs=`openssl s_client -servername $1 -host $1 -port 443 -showcerts </dev/null 2>/dev/null | sed -n '/Certificate chain/,/Server certificate/p'`
    3. rest=$certs
    4. while [[ "$rest" =~ '-----BEGIN CERTIFICATE-----' ]]
    5. do
    6. cert="${rest%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----"
    7. rest=${rest#*-----END CERTIFICATE-----}
    8. echo `echo "$cert" | grep 's:' | sed 's/.*s:\(.*\)/\1/'`
    9. echo "$cert" | openssl x509 -pubkey -noout |
    10. openssl rsa -pubin -outform der 2>/dev/null |
    11. openssl dgst -sha256 -binary | openssl enc -base64
    12. done
    Alles anzeigen
    erhalte.
    Das heißt irgendetwas passt mit der NSData Representation nicht.

    Viele Grüße

    EDIT: Ich habe gesehen, dass wohl der PublicKey nicht ganz korrekt ist und deshalb stimmt der Hash nicht. Der Key den ich mit OpenSSL bekomme beginnt mit MIIBI und der den ich bei iOS bekomme beginnt mit MIIBC. Das heißt, hier läuft was falsch.

    C-Quellcode

    1. CFIndex theCertCount = SecTrustGetCertificateCount(serverTrust);
    2. for (CFIndex theCertIndex = 0; theCertIndex < theCertCount; theCertIndex++) {
    3. SecCertificateRef theCert = SecTrustGetCertificateAtIndex(serverTrust, theCertIndex);
    4. NSData *theData = (__bridge_transfer NSData *)SecCertificateCopyData(theCert);
    5. SecKeyRef publicKey = SecCertificateCopyPublicKey(theCert);
    EDIT2: Ich muss mich korrigieren. Der PublicKey ist korrekt, allerdings fehlt ein Teil. Während der Export von Openssl aus zwei Teilen besteht (MII kommt zwei mal vor), fehlt bei Public Key bei iOS der vordere Part. Um es mal an einem Beispiel zu zeigen, hier der PubKey von google.de


    Quellcode

    1. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylJL6h7/ziRrqNpyGGjV
    2. Vl0OSFotNQl2Ws+kyByxqf5TifutNP+IW5+75+gAAdw1c3UDrbOxuaR9KyZ5zhVA
    3. Cu9RuJ8yjHxwhlJLFv5qJ2vmNnpiUNjfmonMCSnrTykUiIALjzgegGoYfB29lzt4
    4. fUVJNk9BzaLgdlc8aDF5ZMlu11EeZsOiZCx5wOdlw1aEU1pDbcuaAiDS7xpp0bCd
    5. c6LgKmBlUDHP+7MvvxGIQC61SRAPCm7cl/q/LJ8FOQtYVK8GlujFjgEWvKgaTUHF
    6. k5GiHqGL8v7BiCRJo0dLxRMB3adXEmliK+v+IO9p+zql8H4p7u2WFvexH6DkkCXg
    7. MwIDAQAB

    Der besteht aus den Teilen
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A und
    MIIBCgKCAQEAylJL6h7/ziRrqNpyGGjV
    Vl0OSFotNQl2Ws+kyByxqf5TifutNP+IW5+75+gAAdw1c3UDrbOxuaR9KyZ5zhVA
    Cu9RuJ8yjHxwhlJLFv5qJ2vmNnpiUNjfmonMCSnrTykUiIALjzgegGoYfB29lzt4
    fUVJNk9BzaLgdlc8aDF5ZMlu11EeZsOiZCx5wOdlw1aEU1pDbcuaAiDS7xpp0bCd
    c6LgKmBlUDHP+7MvvxGIQC61SRAPCm7cl/q/LJ8FOQtYVK8GlujFjgEWvKgaTUHF
    k5GiHqGL8v7BiCRJo0dLxRMB3adXEmliK+v+IO9p+zql8H4p7u2WFvexH6DkkCXg
    MwIDAQAB

    Hier scheint sich das Outputformat geringfügig zu unterscheiden. Allerdings weiß ich gerade nicht warum.

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von mike09 () aus folgendem Grund: edit

  • Aus irgendeinem Grund unterscheidet sich das DER Format bei iOS von dem bei OpenSSL und Android.
    Das ist der Public Key bei iOS

    Quellcode

    1. MIIBCgKCAQEAylJL6h7/ziRrqNpyGGjVVl0OSFotNQl2Ws+kyByxqf5TifutNP+I
    2. W5+75+gAAdw1c3UDrbOxuaR9KyZ5zhVACu9RuJ8yjHxwhlJLFv5qJ2vmNnpiUNjf
    3. monMCSnrTykUiIALjzgegGoYfB29lzt4fUVJNk9BzaLgdlc8aDF5ZMlu11EeZsOi
    4. ZCx5wOdlw1aEU1pDbcuaAiDS7xpp0bCdc6LgKmBlUDHP+7MvvxGIQC61SRAPCm7c
    5. l/q/LJ8FOQtYVK8GlujFjgEWvKgaTUHFk5GiHqGL8v7BiCRJo0dLxRMB3adXEmli
    6. K+v+IO9p+zql8H4p7u2WFvexH6DkkCXgMwIDAQAB

    Das ist der gleiche Public Key mit OpenSSL oder auch Android

    Quellcode

    1. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylJL6h7/ziRrqNpyGGjV
    2. Vl0OSFotNQl2Ws+kyByxqf5TifutNP+IW5+75+gAAdw1c3UDrbOxuaR9KyZ5zhVA
    3. Cu9RuJ8yjHxwhlJLFv5qJ2vmNnpiUNjfmonMCSnrTykUiIALjzgegGoYfB29lzt4
    4. fUVJNk9BzaLgdlc8aDF5ZMlu11EeZsOiZCx5wOdlw1aEU1pDbcuaAiDS7xpp0bCd
    5. c6LgKmBlUDHP+7MvvxGIQC61SRAPCm7cl/q/LJ8FOQtYVK8GlujFjgEWvKgaTUHF
    6. k5GiHqGL8v7BiCRJo0dLxRMB3adXEmliK+v+IO9p+zql8H4p7u2WFvexH6DkkCXg
    7. MwIDAQAB
    Ich bekomme zwar mittlerweile den Hash errechnet, aber in einem Format das offenbar nur noch bei iOS genutzt wird, und das bringt mir leider nichts. Irgendeine Idee?