2015-10-16 4 views
11

In meiner statischen Bibliothek habe ich eine Lizenzdatei. Was ich sicherstellen möchte, wurde von mir selbst generiert (und wurde nicht verändert). Die Idee war also, eine RSA-Signatur von dem zu verwenden, was ich gelesen habe.Überprüfen der RSA-Signatur iOS

Ich habe im Internet geschaut und das ist, was ich kam mit:

Erstens: Die Erzeugung der privaten Schlüssel und selbstsignierte Zertifikate mit den Informationen, die ich here gefunden.

// Generate private key 
openssl genrsa -out private_key.pem 2048 -sha256 

// Generate certificate request 
openssl req -new -key private_key.pem -out certificate_request.pem -sha256 

// Generate public certificate 
openssl x509 -req -days 2000 -in certificate_request.pem -signkey private_key.pem -out certificate.pem -sha256 

// Convert it to cer format so iOS kan work with it 
openssl x509 -outform der -in certificate.pem -out certificate.cer -sha256 

Danach erstelle ich eine Lizenzdatei (mit einem Datum und einer App Kennung als Inhalt) und eine Signatur für diese Datei wie so erzeugen, die auf der Grundlage der Informationen gefunden here:

// Store the sha256 of the licence in a file 
openssl dgst -sha256 licence.txt > hash 

// And generate a signature file for that hash with the private key generated earlier 
openssl rsautl -sign -inkey private_key.pem -keyform PEM -in hash > signature.sig 

Was ich denke, alles funktioniert gut. Ich bekomme keine Fehler und bekomme die Schlüssel und Zertifikate und andere Dateien wie erwartet.

Als nächstes kopiere ich certificate.cer, signature.sig und license.txt zu meiner Anwendung.

Jetzt möchte ich überprüfen, ob die Signatur von mir signiert wurde und für die Lizenz.txt gültig ist. Ich fand es ziemlich schwer, keine guten Beispiele zu finden, aber das ist, was ich habe zur Zeit:

Die Seucyrity.Framework Ich fand heraus, verwendet ein SecKeyRef ein RSA-Schlüssel/Zertifikat zu referenzieren und SecKeyRawVerify eine Signatur zu verifizieren.

Ich habe die folgende Methode, um den öffentlichen Schlüssel aus einer Datei zu laden.

- (SecKeyRef)publicKeyFromFile:(NSString *) path 
{ 
    NSData *myCertData = [[NSFileManager defaultManager] contentsAtPath:path]; 
    CFDataRef myCertDataRef = (__bridge CFDataRef) myCertData; 

    SecCertificateRef cert = SecCertificateCreateWithData (kCFAllocatorDefault, myCertDataRef); 
    CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **) &cert, 1, NULL); 
    SecPolicyRef policy = SecPolicyCreateBasicX509(); 
    SecTrustRef trust; 
    SecTrustCreateWithCertificates(certs, policy, &trust); 
    SecTrustResultType trustResult; 
    SecTrustEvaluate(trust, &trustResult); 
    SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust); 

    if (trustResult == kSecTrustResultRecoverableTrustFailure) 
    { 
     NSLog(@"I think this is the problem"); 
    } 
    return pub_key_leaf; 
} 

Die basiert auf this SO post.

Für die Signaturprüfung fand ich die folgende Funktion

BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey) 
{ 
    size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey); 
    const void* signedHashBytes = [signature bytes]; 

    size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH; 
    uint8_t* hashBytes = malloc(hashBytesSize); 
    if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { 
     return nil; 
    } 

    OSStatus status = SecKeyRawVerify(publicKey, 
             kSecPaddingPKCS1SHA256, 
             hashBytes, 
             hashBytesSize, 
             signedHashBytes, 
             signedHashBytesSize); 

    return status == errSecSuccess; 
} 

die sich von here

In meinem Projekt der Code wie ich nenne so genommen wird:

es
// Get the licence data 
NSString *licencePath = [[NSBundle mainBundle] pathForResource:@"licence" ofType:@"txt"]; 
NSData *data = [[NSFileManager defaultManager] contentsAtPath:licencePath]; 

// Get the signature data 
NSString *signaturePath = [[NSBundle mainBundle] pathForResource:@"signature" ofType:@"sig"]; 
NSData *signature = [[NSFileManager defaultManager] contentsAtPath:signaturePath]; 

// Get the public key 
NSString *publicKeyPath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"]; 
SecKeyRef publicKey = [self publicKeyFromFile:publicKeyPath]; 

// Check if the signature is valid with this public key for this data 
BOOL result = PKCSVerifyBytesSHA256withRSA(data, signature, publicKey); 

if (result) 
{ 
    NSLog(@"Alright All good!"); 
} 
else 
{ 
    NSLog(@"Something went wrong!"); 
} 

Aktuell sagt immer : "Etwas ist schief gelaufen!" obwohl ich mir nicht sicher bin was. Ich habe herausgefunden, dass das Vertrauen in der Methode resultiert, die den öffentlichen Schlüssel gleich kSecTrustResultRecoverableTrustFailure holt, was ich denke, ist das Problem. In der Apple documentation fand ich, dass das Ergebnis eines Zertifikats sein könnte, das abgelaufen ist. Obwohl das hier nicht der Fall zu sein scheint. Aber vielleicht stimmt etwas nicht mit der Art und Weise, wie ich mein Zertifikat erstelle?

Meine Frage läuft darauf hinaus, was mache ich falsch, und wie könnte ich das beheben? Ich finde die Dokumentation zu diesem Thema sehr spärlich und schwer zu lesen.

Ich habe uploaded ein iOS-Projekt mit generierten Zertifikaten und dem hier referenzierten Code. Vielleicht könnte das nützlich sein.

+1

Wenn man sich anschaut, 3- Listing In der Dokumentation, auf die Sie verwiesen haben, sehen Sie 5 "AllStatusBits". Können Sie herausfinden, was die Statusbits sind, wenn Sie auf diesen Fehler stoßen? –

+0

Hallo, wenn ich versuche, diesen Code zu integrieren, ist einer der ersten Fehler, dass der Typ 'CSSM_TP_APPLE_CERT_STATUS' von' AllStatusBits' unbekannt ist und ich kann keine funktionierende Header-Datei finden, die diesen Typ enthält. Im Internet habe ich festgestellt, dass es "#import " sein könnte, aber das gibt es (nicht mehr) auf iOS. - Ich habe mein Projekt mit Code und Zertifikaten hochgeladen (http://up.indev.nl/RTR4y0Ou0L.zip), vielleicht hilft das. – Matthijn

+0

Ja, ich habe es einfach überprüft, aber ich habe [bereits] (http://up.indev.nl/C5OHOFziPO.png) das Sicherheitsframework hinzugefügt. Vielleicht wurde das woanders in einer iOS-Version verschoben? – Matthijn

Antwort

8

Das Problem liegt auf dem Weg, auf dem Sie die Signaturdatei erstellen; Nach dem gleichen Schritt konnte ich die binäre Entsprechung signature.sig Datei erzeugen.

Mit einem Blick in der hash Datei können wir sehen, OpenSSL einige Präfixe hinzufügen (und Hex kodieren den Hash):

$ cat hash 
SHA256(licence.txt)= 652b23d424dd7106b66f14c49bac5013c74724c055bc2711521a1ddf23441724 

So signature.sig wird auf dieser Grundlage und nicht auf license.txt

Durch Ihre Probe mit und die Schaffung der Unterzeichnung Datei mit:

openssl dgst -sha256 -sign certificates/private_key.pem licence.txt > signature.sig 

die Hashing & Unterzeichnung ste p bekommt richtig, und die Probe Ausgänge: Alright All good!


Der Endzustand meiner Datei, nur für den Fall

- (SecKeyRef)publicKeyFromFile:(NSString *) path 
{ 
    NSData * certificateData = [[NSFileManager defaultManager] contentsAtPath:path]; 
    SecCertificateRef certificateFromFile = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData); 
    SecPolicyRef secPolicy = SecPolicyCreateBasicX509(); 
    SecTrustRef trust; 
    SecTrustCreateWithCertificates(certificateFromFile, secPolicy, &trust); 
    SecTrustResultType resultType; 
    SecTrustEvaluate(trust, &resultType); 
    SecKeyRef publicKey = SecTrustCopyPublicKey(trust); 
    return publicKey; 
} 

BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey) 
{ 
    uint8_t digest[CC_SHA256_DIGEST_LENGTH]; 
    if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], digest)) 
     return NO; 

    OSStatus status = SecKeyRawVerify(publicKey, 
             kSecPaddingPKCS1SHA256, 
             digest, 
             CC_SHA256_DIGEST_LENGTH, 
             [signature bytes], 
             [signature length]); 

    return status == errSecSuccess; 
} 

PS: die malloc war ein Leck


Edit:

Um Ihre aktuelle signature.sig Datei als as-i arbeiten zu lassen s, können Sie den gleichen Schritt wie openssl produzieren (fügen Präfix, hex-Hash und einem Newline \n), diese Daten dann an SecKeyRawVerify mit kSecPaddingPKCS1 passieren und nicht kSecPaddingPKCS1SHA256:

BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey) 
{ 
    uint8_t digest[CC_SHA256_DIGEST_LENGTH]; 
    if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], digest)) 
     return NO; 

    NSMutableString *hashFile = [NSMutableString stringWithFormat:@"SHA256(licence.txt)= "]; 
    for (NSUInteger index = 0; index < sizeof(digest); ++index) 
     [hashFile appendFormat:@"%02x", digest[index]]; 

    [hashFile appendString:@"\n"]; 
    NSData *hashFileData = [hashFile dataUsingEncoding:NSNonLossyASCIIStringEncoding]; 

    OSStatus status = SecKeyRawVerify(publicKey, 
             kSecPaddingPKCS1, 
             [hashFileData bytes], 
             [hashFileData length], 
             [signature bytes], 
             [signature length]); 

    return status == errSecSuccess; 
} 
+0

Sie erhalten zwar noch eine 'kSecTrustResultRecoverableTrustFailure' in der' SecTrustEvaluate', aber die Signatur wird erfolgreich verifiziert. – Lefteris

+0

Ich denke, das kSecTrustResultRecoverableTrustFailure-Problem ist, dass Ihr Zertifikat selbstsigniert ist, wenn Sie die gesamte Vertrauenskette erfolgreich abschließen möchten gültig sein; Sie müssen ein Zertifikat von einer vertrauenswürdigen Autorität (Apple) erhalten. (ver * s * gn oder dergleichen) – blld

+0

oder installieren Sie Ihr Zertifikat auf dem Host-iOS-Gerät (das scheint keine Option zu sein) – blld