A partir de IOS 10, se es posible importar claves privadas PEM sin convertirlas a PKCS # 12 (que es un formato de contenedor muy universal para todo lo relacionado con la criptografía) y por lo tanto también sin usar OpenSSL en la línea de comandos o vincular estáticamente aplicaciones con él . En macOS, incluso es posible desde 10.7 utilizando una función diferente a las mencionadas aquí (pero hasta ahora no existe para iOS). Exactamente del modo descrito a continuación también funcionará en macOS 10.12 y posteriores.
Para importar un certificado, es suficiente con sólo quitar los
-----BEGIN CERTIFICATE-----
y
-----END CERTIFICATE-----
líneas, a continuación, ejecutar la decodificación base 64 a través de los datos que quedan, el resultado es un certificado en formato DER norma , que solo se puede alimentar a SecCertificateCreateWithData()
para obtener un SecCertificateRef
. Esto siempre ha funcionado, también antes de iOS 10.
Para importar una clave privada, puede que se requiera un poco de trabajo adicional. Si la clave privada se envuelve con
-----BEGIN RSA PRIVATE KEY-----
entonces es muy fácil. De nuevo, la primera y la última línea deben ser eliminadas, los datos restantes deben ser decodificados en base64 y el resultado es una clave RSA en formato PKCS # 1.Este formato solo puede contener claves RSA y es directamente legible, solo alimente los datos decodificados en SecKeyCreateWithData()
para obtener un SecKeyRef
. El diccionario attributes
sólo necesitan los siguientes pares clave/valor:
kSecAttrKeyType
: kSecAttrKeyTypeRSA
kSecAttrKeyClass
: kSecAttrKeyClassPrivate
kSecAttrKeySizeInBits
: CFNumberRef
con el entonces número de bits en la clave (por ejemplo, 1024, 2048, etc.) Si no se conoce, esta información se puede leer a partir de los datos clave sin procesar, que son datos ASN.1 (está un poco fuera del alcance de esta respuesta, pero a continuación proporcionaré algunos enlaces útiles sobre cómo analizar ese formato). ¡Este valor es tal vez opcional! En mis pruebas, en realidad no fue necesario establecer este valor; si está ausente, la API determinó el valor por sí misma y siempre se configuró correctamente más adelante.
En caso de que la clave privada está envuelto por -----BEGIN PRIVATE KEY-----
, los datos a continuación, los base64 no está en PKCS # 1 formato pero en PKCS # 8 formato, sin embargo, este es un sólo un contenedor más genérico que también llevar a cabo llaves no RSA pero para claves RSA los datos internos de ese recipiente es igual a PKCS # 1, por lo que se podría decir de claves RSA PKCS # 8 es PKCS # 1 con una cabecera adicional y todo lo que necesitas hacer es quitar ese encabezado extra. Simplemente elimine los primeros 26 bytes de los datos decodificados de base64 y tiene PKCS # 1 nuevamente. Sí, es así de simple.
Para obtener más información sobre los formatos PKCS # x en las codificaciones PEM, have a look at this site. Para obtener más información sobre el formato ASN.1, here's a good site for that. Y si necesita un analizador de ASN.1 en línea sencillo pero potente e interactivo para jugar con diferentes formatos, uno que pueda leer directamente datos de PEM, así como ASN.1 en base64 y hexdump, try this site.
Muy importante: Al agregar una clave privada al llavero que usted creó como se indica arriba, tenga en cuenta que dicha clave privada no contiene un hash de clave pública, pero un hash de clave pública es importante para el llavero API para formar una identidad (SecIdentityRef
), ya que usar el hash de clave pública es la forma en que la API encuentra la clave privada correcta que pertenece a un certificado importado (un SecIdentityRef
es solo SecKeyRef
de una clave privada y SecCertificateRef
de un certificado que forma una combinación objeto y es el hash de clave pública, que los une). Por lo tanto, cuando planee agregar la clave privada al llavero, asegúrese de configurar un hash de clave pública manualmente; de lo contrario, nunca podrá obtener una identidad y sin eso no podrá usar la API de llavero para tareas como firmar o descifrar datos. El hash de clave pública debe almacenarse en un atributo llamado kSecAttrApplicationLabel
(nombre estúpido, lo sé, pero en realidad no es una etiqueta y nada que el usuario pueda ver nunca, consulte la documentación). Por ejemplo:
OSStatus error = SecItemAdd(
(__bridge CFDictionaryRef)@{
(__bridge NSString *)kSecClass:
(__bridge NSString *)kSecClassKey,
(__bridge NSString *)kSecAttrApplicationLabel:
hashOfPublicKey, // hashOfPublicKey is NSData *
#if TARGET_OS_IPHONE
(__bridge NSString *)kSecValueRef:
(__bridge id)privateKeyToAdd, // privateKeyToAdd is SecKeyRef
#else
(__bridge NSString *)kSecUseItemList:
@[(__bridge id)privateKeyToAdd], // privateKeyToAdd is SecKeyRef
#endif
},
&outReference // Can also be NULL,
// otherwise reference to added keychain entry
// that must be released with CFRelease()
);
creo que encontrará su respuesta aquí: http://stackoverflow.com/questions/1595013/iphone-how-to-create-a-seckeyref-from-a-public-key-file-pem –