Pergunta

I need to verify in Xcode digitally signed piece of data (signed in PHP with private key) using public key. I generated key pair in iOS in command line and both keys are in .pem format. I followed this example in order to do generate it and subsequently verify data in Xcode. However I keep failing to store and get my public key from key chain in SecKeyRef format. Problem is I keep getting NSData object == NULL from stripPublicKeyHeader function, therefore my program crashes on line: [peerPublicKeyAttr setObject:publicKeyData forKey:(id)CFBridgingRelease(kSecValueData)]; in addPeerPublicKey function. Can you please check this peace of code and help with determining the problems, or does anybody have a working solution to verify signed data using public key from a .pem file?

thank you very much in advance.

#include <CoreFoundation/CoreFoundation.h>
#import "NSData+Base64.h"
#import "ViewController.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
#include <Security/Security.h>

-(void)VerifyMyData{

NSString* path = [[NSBundle mainBundle] pathForResource:@"MY_Public_Key" ofType:@"pem"];
NSString* content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];  //retrieve public key content, this is OK
NSString *publicKey;
NSString *startPublicKey = @"-----BEGIN PUBLIC KEY-----";
NSString *endPublicKey = @"-----END PUBLIC KEY-----";
NSScanner *scanner = [NSScanner scannerWithString:content];
[scanner scanUpToString:startPublicKey intoString:nil];
[scanner scanString:startPublicKey intoString:nil];
[scanner scanUpToString:endPublicKey intoString:&publicKey];

 //remoteLog is our function to log our logs
[ViewController remoteLog:[NSString stringWithFormat:@"Public key path:%@",path] withlevel:SPECIAL_LOG];
[ViewController remoteLog:[NSString stringWithFormat:@"Public key content:%@",content] withlevel:SPECIAL_LOG];
[ViewController remoteLog:[NSString stringWithFormat:@"content of public key without tags: %@",publicKey] withlevel:SPECIAL_LOG];

NSData *d_key = [NSData dataFromBase64String:content];
NSData *strippedKey =  [ViewController stripPublicKeyHeader:d_key];
NSString *StringtoDecode = [[NSBundle mainBundle]objectForInfoDictionaryKey:@"expirySetYear"];

 if (d_key == NULL) {
    [ViewController remoteLog:@"No data in d_key" withlevel:SPECIAL_LOG];
 }
 if (strippedKey == NULL) {
    [ViewController remoteLog:@"No data in strippedKey" withlevel:SPECIAL_LOG];
 } 
 //in this function it crashes because of strippedKey ==NULL
 [ViewController addPeerPublicKey:@"MIA_KEY" keyBits:strippedKey]; 
}


+ (NSData *)stripPublicKeyHeader:(NSData *)d_key
{
// Skip ASN.1 public key header
if (d_key == nil) {
    [ViewController remoteLog:@"stripPublicKeyHeader: d_key == nil" withlevel:SPECIAL_LOG];
    return(nil);
}

unsigned int len = [d_key length];
if (!len) {
    [ViewController remoteLog:@"stripPublicKeyHeader: length of d_key == nil" withlevel:SPECIAL_LOG];
    return(nil);
}

unsigned char *c_key = (unsigned char *)[d_key bytes];
unsigned int  idx    = 0;

if (c_key[idx++] != 0x30) {
    [ViewController remoteLog:@"stripPublicKeyHeader: section 0" withlevel:SPECIAL_LOG];
    return(nil);
}

if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
else idx++;

// PKCS #1 rsaEncryption szOID_RSA_RSA
static unsigned char seqiod[] =
{ 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
    0x01, 0x05, 0x00 };
if (memcmp(&c_key[idx], seqiod, 15)) {
    [ViewController remoteLog:@"stripPublicKeyHeader: section 1" withlevel:SPECIAL_LOG];
    return(nil);
}

idx += 15;

if (c_key[idx++] != 0x03) {
    [ViewController remoteLog:@"stripPublicKeyHeader: section 2" withlevel:SPECIAL_LOG];
    return(nil);
}

if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
else idx++;

if (c_key[idx++] != '\0') {
    [ViewController remoteLog:@"stripPublicKeyHeader: section 3" withlevel:SPECIAL_LOG];
    return(nil);
}

  // Now make a new NSData from this buffer   *****THIS IS PROBABLY PROBLEM*****
  return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}

+ (void)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKeyData {

OSStatus sanityCheck = noErr;
CFTypeRef persistPeer = NULL;
//[self removePeerPublicKey:peerName];

NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];

[peerPublicKeyAttr setObject:(id)CFBridgingRelease(kSecClassKey) forKey:(id)CFBridgingRelease(kSecClass)];
[peerPublicKeyAttr setObject:(id)CFBridgingRelease(kSecAttrKeyTypeRSA) forKey:(id)CFBridgingRelease(kSecAttrKeyType)];
[peerPublicKeyAttr setObject:peerTag forKey:(id)CFBridgingRelease(kSecAttrApplicationTag)];
[peerPublicKeyAttr setObject:publicKeyData forKey:(id)CFBridgingRelease(kSecValueData)];
[peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)CFBridgingRelease(kSecReturnData)];
sanityCheck = SecItemAdd((CFDictionaryRef) CFBridgingRetain(peerPublicKeyAttr), (CFTypeRef *)&persistPeer);


if(sanityCheck == errSecDuplicateItem){
    //TRC_DBG(@"Problem adding the peer public key to the keychain, OSStatus == %ld.", sanityCheck );
}

//TRC_DBG(@"SecItemAdd OSStATUS = %ld", sanityCheck);

//        TRC_DBG(@"PersistPeer privatekey data after import into keychain %@", persistPeer);
persistPeer = NULL;
[peerPublicKeyAttr removeObjectForKey:(id)CFBridgingRelease(kSecValueData)];
sanityCheck = SecItemCopyMatching((CFDictionaryRef) CFBridgingRetain(peerPublicKeyAttr), (CFTypeRef*)&persistPeer);

//TRC_DBG(@"SecItemCopying OSStATUS = %ld", sanityCheck);
//        TRC_DBG(@"SecItem copy matching returned this public key data %@", persistPeer);
// The nice thing about persistent references is that you can write their value out to disk and
// then use them later. I don't do that here but it certainly can make sense for other situations
// where you don't want to have to keep building up dictionaries of attributes to get a reference.
//
// Also take a look at SecKeyWrapper's methods (CFTypeRef)getPersistentKeyRefWithKeyRef:(SecKeyRef)key
// & (SecKeyRef)getKeyRefWithPersistentKeyRef:(CFTypeRef)persistentRef.
//[peerTag release];
//[peerPublicKeyAttr release];
if (persistPeer) CFRelease(persistPeer);
}
Foi útil?

Solução

It looks like you should be Base64-decoding publicKey, not content? That would explain why you're getting NULL in stripPublicKeyHeader.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top