Nella mia libreria statica ho un file di licenza. Che voglio essere sicuro sia stato generato da me stesso (e non sia stato alterato). Quindi l'idea era di usare una firma RSA da quello che ho letto.Verifica firma RSA iOS
Ho guardato su internet e questo è ciò che mi si avvicinò con:
Primo: La generazione delle chiavi private e certificati self firmato con le informazioni che ho trovato here.
// 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
Dopo di che, ho creare un file di licenza (con una data e app identificatore come contenuti) e generare una firma per il file in questo modo sulla base delle informazioni trovate 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
Che io pensa che tutto funzioni bene. Non ricevo errori e ottengo chiavi, certificati e altri file come previsto.
Successivamente, copio certificate.cer
, signature.sig
e license.txt
alla mia applicazione.
Ora voglio controllare se la firma è stata firmata da me ed è valida per license.txt. L'ho trovato abbastanza difficile trovare dei buoni esempi, ma questo è quello che ho attualmente:
Il Seucyrity.Framework
ho scoperto che utilizza un SecKeyRef
fare riferimento a un RSA chiave/certificato e SecKeyRawVerify
per verificare una firma.
Ho il seguente metodo per caricare la chiave pubblica da un file.
- (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;
}
Quale è basato su this messaggio SO.
Per la convalida della firma ho trovato la seguente funzione
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;
}
che è tratto da here
Nel mio progetto che io chiamo il codice in questo modo:
// 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!");
}
Attualmente dice sempre : "Qualcosa è andato storto!" anche se non sono sicuro di cosa. Ho scoperto che il risultato della fiducia nel metodo che recupera la chiave pubblica equivale a kSecTrustResultRecoverableTrustFailure
che penso sia il problema. Nel Apple documentation ho scoperto che potrebbe essere il risultato di un certificato che è scaduto. Anche se non sembra essere il caso qui. Ma forse c'è qualcosa di sbagliato nel modo in cui generi il mio certificato?
La mia domanda si riduce a, cosa sto sbagliando, e come potrei risolverlo? Trovo la documentazione su questo piuttosto scarso e difficile da leggere.
Ho uploaded un progetto iOS con certificati generati e il codice di riferimento qui. Forse potrebbe tornare utile.
Se si guarda a Listing 3- 5 nella documentazione che hai indicato, lo vedrai elencando "' AllStatusBits' ". Riesci a capire quali sono i bit di stato quando incontri quell'errore? –
Salve, quando provo a incorporare quel codice uno dei primi errori è che il tipo 'CSSM_TP_APPLE_CERT_STATUS' di' AllStatusBits' è sconosciuto e non riesco a trovare un file di intestazione funzionante da includere per ottenere quel tipo. Su internet ho scoperto che potrebbe essere "#import" ma che non esiste più (più?) Su iOS. - Ho [caricato] (http://up.indev.nl/RTR4y0Ou0L.zip) il mio progetto con il codice e i certificati, forse questo aiuta. –
Matthijn
Sì, ho appena controllato due volte, ma ho già [già] (http://up.indev.nl/C5OHOFziPO.png) l'aggiunta del framework Security. Forse è stato spostato da qualche altra parte in una versione iOS? – Matthijn