Aceptar certificate de server SSL no confiable con socket CFStream en iOS

Necesito abrir una connection de socket CFStream a un server que tiene una raíz de CA no confiable. Tengo el certificate del server y puedo crear una estructura SecCertificateRef . El problema es cómo configurar las properties de la transmisión.

Creo que debería establecer la propiedad kCFStreamPropertySSLSettings en un CFDictionary que a su vez contenga una key kCFStreamSSLCertificates . Esta key debe contener una "a CFArray de SecCertificateRefs excepto para el primer elemento en la matriz, que es un SecIdentityRef" de acuerdo con los documentos. Ahora puedo crear el SecCertificateRef desde el certificate del server que enviaré con la aplicación, pero ¿cómo get el SecIdentityRef ? Supongo que debería ser la identidad del cliente, pero por ahora no quiero authentication del lado del cliente . Y no puedo encontrar una forma de alimentar CFStream solo con el certificate del server.

Tenga en count que no deseo agregar el certificate que no es de confianza al llavero, ni deshabilitar kCFStreamSSLValidatesCertificateChain en la configuration. Necesito aceptar la authentication del server solo si se basa en mis propios datos de certificate del server cargados desde el disco, y solo en este CFStream.

No tengo la respuesta directa a su pregunta, pero tal vez algunas pautas:

  1. ¿Por qué necesita utilizar la API CFStream y no la NSURLConnection más intuitiva?
    Por lo que pude encontrar en la documentation, no todo lo que está disponible para Mac OS X, con respecto a CFStream API, está disponible para iOS. Así que piensa en ello y mira si puedes cambiar a NSURLConnection 🙂

  2. Para NSURLConnection, puede usar los methods NSURLConnectionDelegate para get el desafío de SSL y validar el certificate por su count. Puede verificar el proyecto wsdl2objc , donde implementé estas características:

  3. Ahora sobre sus preguntas 🙂
    No veo cómo puede establecer una CA personalizada (no confiable) en kCFStreamPropertySSLSettings . No estoy seguro de si se puede hacer utilizando kCFStreamSSLCertificates, ya que está destinado a ser utilizado para establecer certificates del lado del cliente (por lo tanto, el requisito de tener SecIdentityRef en el índice 0, que básicamente proporciona la key privada).

  4. Cuando dices que no quieres agregar el certificate al llavero, ¿quieres decir de forma manual o programática? Supongo que no te gusta que los usuarios de tu aplicación tengan que hacerlo manualmente, pero puedes usar la API de security para importar el certificate de manera progtwigda. En este caso, su certificate se importará en un llavero de espacio aislado que solo está disponible para su aplicación. (de nuevo, no estoy seguro de si esto funcionará, pero vale la pena intentarlo)

En mis aplicaciones utilizo NSURLConnectionDelegate para validar manualmente los certificates que no son de confianza.

Saludos,
Pece

Básicamente tienes que:

  1. deshabilite la evaluación de confianza pnetworkingeterminada utilizando kCFStreamSSLValidatesCertificateChain
  2. obtenga el object de confianza ( kCFStreamPropertySSLPeerTrust ) una vez conectado al flujo (pero antes de enviar cualquier dato, es decir, en events kCFStreamEventCanAcceptBytes o kCFStreamEventHasBytesAvailable )
  3. establezca su certicate de raíz autofirmado como un ancla de confianza para ese object de confianza
  4. opcionalmente, puede agregar políticas SSL personalizadas al object de confianza (por ejemplo, el nombre de host no coincide con el certificate CN), pero si lo hace es importante que lo haga antes de establecer el anclaje de confianza o puede get el resultado kSecTrustResultRecoverableTrustFailure
  5. evalúe el object de confianza ( SecTrustEvaluate ) y verifique que el resultado sea kSecTrustResultProceed o kSecTrustResultUnspecified