2012-06-13 14 views
7

Lo que estoy tratando de hacer es replicar la siguiente instrucción ejecutada a través de terminales en un Mac, pero en el iPhone/en Cocoa:Replicar OpenSSL smime en el iPhone/Cacao

openssl smime -binary -sign -signer cert.pem -inkey key.pem -in file.txt -out encrypted -outform DER 

donde "encriptada" es el archivo encriptado que resulta del comando.

Aunque especifica 2 claves separadas (clave pública y privada), es posible tenerlas como un único archivo .p12.

Después de seguir this cocoa snippet para encriptar un archivo usando un certificado .p12, no estoy seguro si este es el camino correcto a seguir.

¿Cuál es el mejor enfoque para replicar el comando smime en un iPhone (según el comando Terminal anterior), o no es posible en absoluto a través de los métodos disponibles Security.framework/CommonCrypto?

+0

No sé la respuesta, pero ¡buena suerte en su aplicación PassKit! –

Respuesta

3

Por lo que yo sé, usted está un poco en un riachuelo, con la paleta encerrada en la tienda de aplicaciones.

  • iOS carece CMSEncoderAddSigners, CMSEncoderUpdateContent, CMSEncoderCopyEncodedContent que se necesita para esto.
  • El uso de openssl o Chilkat tampoco es ideal, ya que la API de llavero de iOS no le da acceso (más) a la clave privada una vez importada.

He resuelto esto en el pasado tanto con openssl como con Chilkat.

En cada caso, sin embargo, 'guardo' una copia de la clave privada, ya que una vez que ingresa en el llavero, todo lo que puedo recuperar es un SecKeyRef (debe firmar un acuerdo/permiso adicional con apple to be capaz de volver a salir y aún estar en la tienda de aplicaciones. Invertir ingeniería de cualquiera de las aplicaciones de VPN (por ejemplo, el enebro uno) para ver los métodos/marco para vincular).

Para openssl - simplemente tome el código smime.c en las aplicaciones de openssl y modifique. Para que las cosas chilkat son mucho más simple:

CkoCert * mine = [identity ckoCert]; 

    assert([mime AddEncryptCert: mine] == YES); 

    for(id cc in backupCerts) { 
     assert([mime AddEncryptCert:cc] == YES); 
    } 

    for(id key in [headers allKeys]) { 
     [mime SetHeaderField:[NSString stringWithFormat:@"%s%@", X_HDR_PREFIX, key] 
         value:[headers objectForKey:key] 
     ]; 
    }; 

    [mime SetBodyFromBinary:data];   
    assert([mime EncryptN] == YES); 

    return [mime GetMimeBytes]; 

y donde el campo de identidad tiene la 'mantener su propia caché' tramposo:

-(id)initWithPKCS12:(NSData*)pkcs12der password:(NSString *)password { 
    if (password == nil) 
     password = [APPSETTINGS wellKnownPkcsPassword]; 

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          password, kSecImportExportPassphrase, 
          nil]; 

    CFArrayRef items; 
    OSStatus status = SecPKCS12Import((__bridge CFDataRef)pkcs12der, 
     (__bridge CFDictionaryRef)options, &items); 

    if (status != noErr) { 
     NSLog(@"PKCS12 importAsDer failed: Error %ld",(long)status); 
     ... 
    } 

    if (!items || CFArrayGetCount(items) < 1) { 
     NSLog(@"PKCS12 importAsDer failed - nothing returned (%ld bytes DER)", 
       (long)[pkcs12der length]); 
     ... 
    } 

    CFDictionaryRef dict0 = (CFDictionaryRef) CFArrayGetValueAtIndex(items, 0); 
    if (!dict0) 
     return nil; 

    SecIdentityRef iRef = (SecIdentityRef) CFDictionaryGetValue(dict0, 
      kSecImportItemIdentity); 
    CFArrayRef cRef = (CFArrayRef) CFDictionaryGetValue(dict0, kSecImportItemCertChain); 

    self = [self initWithIdentityRef:iRef withChainArrayRef:cRef]; 
    CFRelease(items); 

#if TARGET_OS_IPHONE 
    // We lack SecPrivate* on iOS. So we cheat a bit - rather than 
    // use the keychain we limt ourselves to our own *.p12's and 
    // keep a copy of the private key in memory. 
    // 
# ifdef WITH_OPENSSL 

    const unsigned char * ptr = [pkcs12der bytes]; 
    PKCS12 * p12 = d2i_PKCS12(NULL, &ptr, len); 
    char buff[1024]; 

    if (!p12) { 
     NSLog(@"Could not decode PKCS#12: %s", ERR_error_string(ERR_get_error(), buff)); 
     ... 
    }; 

    const char * pass = [password cStringUsingEncoding:NSASCIIStringEncoding]; 

    if (PKCS12_parse(p12, pass, &pkey, &x509, NULL) != 1) { 
     NSLog(@"Could not parse PKCS#12: %s", ERR_error_string(ERR_get_error(), buff)); 
     ... 
    }; 
    .... 
# else 
    ckoCert = [[CkoCert alloc] init]; 

    if (!([ckoCert LoadPfxData:pkcs12der password:[APPSETTINGS wellKnownPkcsPassword]])) { 
     NSLog(@"PKCS12 loadPfxData failed: %@", [ckoCert LastErrorText]); 
     ... 
    } 

    ckoPrivateKey = [ckoCert ExportPrivateKey]; 
# endif // chilkat or openssl 
#endif // iOS 

    return self; 
} 

Advertencia: en la mayor parte de gestión MNGT/error anterior que he desnudado y/o lo reemplazó por afirma, ya que de lo contrario, se puso un poco demasiado manejable.

Gracias,

Dw.