static CURLcode sectransp_connect_step2()

in libs/curl/lib/vtls/sectransp.c [1944:2271]


static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
                                        struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  OSStatus err;
  SSLCipherSuite cipher;
  SSLProtocol protocol = 0;

  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);
  DEBUGASSERT(backend);
  CURL_TRC_CF(data, cf, "connect_step2");

  /* Here goes nothing: */
check_handshake:
  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  err = SSLHandshake(backend->ssl_ctx);

  if(err != noErr) {
    switch(err) {
      case errSSLWouldBlock:  /* they are not done with us yet */
        connssl->io_need = backend->ssl_direction ?
            CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
        return CURLE_OK;

      /* The below is errSSLServerAuthCompleted; it is not defined in
        Leopard's headers */
      case -9841:
        if((conn_config->CAfile || conn_config->ca_info_blob) &&
           conn_config->verifypeer) {
          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
                                        conn_config->ca_info_blob,
                                        backend->ssl_ctx);
          if(result)
            return result;
        }
        /* the documentation says we need to call SSLHandshake() again */
        goto check_handshake;

      /* Problem with encrypt / decrypt */
      case errSSLPeerDecodeError:
        failf(data, "Decode failed");
        break;
      case errSSLDecryptionFail:
      case errSSLPeerDecryptionFail:
        failf(data, "Decryption failed");
        break;
      case errSSLPeerDecryptError:
        failf(data, "A decryption error occurred");
        break;
      case errSSLBadCipherSuite:
        failf(data, "A bad SSL cipher suite was encountered");
        break;
      case errSSLCrypto:
        failf(data, "An underlying cryptographic error was encountered");
        break;
#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
      case errSSLWeakPeerEphemeralDHKey:
        failf(data, "Indicates a weak ephemeral Diffie-Hellman key");
        break;
#endif

      /* Problem with the message record validation */
      case errSSLBadRecordMac:
      case errSSLPeerBadRecordMac:
        failf(data, "A record with a bad message authentication code (MAC) "
                    "was encountered");
        break;
      case errSSLRecordOverflow:
      case errSSLPeerRecordOverflow:
        failf(data, "A record overflow occurred");
        break;

      /* Problem with zlib decompression */
      case errSSLPeerDecompressFail:
        failf(data, "Decompression failed");
        break;

      /* Problem with access */
      case errSSLPeerAccessDenied:
        failf(data, "Access was denied");
        break;
      case errSSLPeerInsufficientSecurity:
        failf(data, "There is insufficient security for this operation");
        break;

      /* These are all certificate problems with the server: */
      case errSSLXCertChainInvalid:
        failf(data, "SSL certificate problem: Invalid certificate chain");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLUnknownRootCert:
        failf(data, "SSL certificate problem: Untrusted root certificate");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLNoRootCert:
        failf(data, "SSL certificate problem: No root certificate");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLCertNotYetValid:
        failf(data, "SSL certificate problem: The certificate chain had a "
                    "certificate that is not yet valid");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLCertExpired:
      case errSSLPeerCertExpired:
        failf(data, "SSL certificate problem: Certificate chain had an "
              "expired certificate");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLBadCert:
      case errSSLPeerBadCert:
        failf(data, "SSL certificate problem: Couldn't understand the server "
              "certificate format");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLPeerUnsupportedCert:
        failf(data, "SSL certificate problem: An unsupported certificate "
                    "format was encountered");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLPeerCertRevoked:
        failf(data, "SSL certificate problem: The certificate was revoked");
        return CURLE_PEER_FAILED_VERIFICATION;
      case errSSLPeerCertUnknown:
        failf(data, "SSL certificate problem: The certificate is unknown");
        return CURLE_PEER_FAILED_VERIFICATION;

      /* These are all certificate problems with the client: */
      case errSecAuthFailed:
        failf(data, "SSL authentication failed");
        break;
      case errSSLPeerHandshakeFail:
        failf(data, "SSL peer handshake failed, the server most likely "
              "requires a client certificate to connect");
        break;
      case errSSLPeerUnknownCA:
        failf(data, "SSL server rejected the client certificate due to "
              "the certificate being signed by an unknown certificate "
              "authority");
        break;

      /* This error is raised if the server's cert did not match the server's
         hostname: */
      case errSSLHostNameMismatch:
        failf(data, "SSL certificate peer verification failed, the "
              "certificate did not match \"%s\"\n", connssl->peer.dispname);
        return CURLE_PEER_FAILED_VERIFICATION;

      /* Problem with SSL / TLS negotiation */
      case errSSLNegotiation:
        failf(data, "Could not negotiate an SSL cipher suite with the server");
        break;
      case errSSLBadConfiguration:
        failf(data, "A configuration error occurred");
        break;
      case errSSLProtocol:
        failf(data, "SSL protocol error");
        break;
      case errSSLPeerProtocolVersion:
        failf(data, "A bad protocol version was encountered");
        break;
      case errSSLPeerNoRenegotiation:
        failf(data, "No renegotiation is allowed");
        break;

      /* Generic handshake errors: */
      case errSSLConnectionRefused:
        failf(data, "Server dropped the connection during the SSL handshake");
        break;
      case errSSLClosedAbort:
        failf(data, "Server aborted the SSL handshake");
        break;
      case errSSLClosedGraceful:
        failf(data, "The connection closed gracefully");
        break;
      case errSSLClosedNoNotify:
        failf(data, "The server closed the session with no notification");
        break;
      /* Sometimes paramErr happens with buggy ciphers: */
      case paramErr:
      case errSSLInternal:
      case errSSLPeerInternalError:
        failf(data, "Internal SSL engine error encountered during the "
              "SSL handshake");
        break;
      case errSSLFatalAlert:
        failf(data, "Fatal SSL engine error encountered during the SSL "
              "handshake");
        break;
      /* Unclassified error */
      case errSSLBufferOverflow:
        failf(data, "An insufficient buffer was provided");
        break;
      case errSSLIllegalParam:
        failf(data, "An illegal parameter was encountered");
        break;
      case errSSLModuleAttach:
        failf(data, "Module attach failure");
        break;
      case errSSLSessionNotFound:
        failf(data, "An attempt to restore an unknown session failed");
        break;
      case errSSLPeerExportRestriction:
        failf(data, "An export restriction occurred");
        break;
      case errSSLPeerUserCancelled:
        failf(data, "The user canceled the operation");
        break;
      case errSSLPeerUnexpectedMsg:
        failf(data, "Peer rejected unexpected message");
        break;
#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
      /* Treating non-fatal error as fatal like before */
      case errSSLClientHelloReceived:
        failf(data, "A non-fatal result for providing a server name "
                    "indication");
        break;
#endif

      /* Error codes defined in the enum but should never be returned.
         We list them here just in case. */
#if CURL_BUILD_MAC_10_6
      /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */
      case errSSLClientCertRequested:
        failf(data, "Server requested a client certificate during the "
              "handshake");
        return CURLE_SSL_CLIENTCERT;
#endif
#if CURL_BUILD_MAC_10_9
      /* Alias for errSSLLast, end of error range */
      case errSSLUnexpectedRecord:
        failf(data, "Unexpected (skipped) record in DTLS");
        break;
#endif
      default:
        /* May also return codes listed in Security Framework Result Codes */
        failf(data, "Unknown SSL protocol error in connection to %s:%d",
              connssl->peer.hostname, err);
        break;
    }
    return CURLE_SSL_CONNECT_ERROR;
  }
  else {
    char cipher_str[64];
    /* we have been connected fine, we are not waiting for anything else. */
    connssl->connecting_state = ssl_connect_3;

#ifdef SECTRANSP_PINNEDPUBKEY
    if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
      CURLcode result =
        pkp_pin_peer_pubkey(data, backend->ssl_ctx,
                            data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
      if(result) {
        failf(data, "SSL: public key does not match pinned public key");
        return result;
      }
    }
#endif /* SECTRANSP_PINNEDPUBKEY */

    /* Informational message */
    (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
    (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);

    sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
                                   sizeof(cipher_str), true);
    switch(protocol) {
      case kSSLProtocol2:
        infof(data, "SSL 2.0 connection using %s", cipher_str);
        break;
      case kSSLProtocol3:
        infof(data, "SSL 3.0 connection using %s", cipher_str);
        break;
      case kTLSProtocol1:
        infof(data, "TLS 1.0 connection using %s", cipher_str);
        break;
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
      case kTLSProtocol11:
        infof(data, "TLS 1.1 connection using %s", cipher_str);
        break;
      case kTLSProtocol12:
        infof(data, "TLS 1.2 connection using %s", cipher_str);
        break;
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
      case kTLSProtocol13:
        infof(data, "TLS 1.3 connection using %s", cipher_str);
        break;
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
      default:
        infof(data, "Unknown protocol connection");
        break;
    }

#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
    defined(HAVE_BUILTIN_AVAILABLE)
    if(connssl->alpn) {
      if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
        CFArrayRef alpnArr = NULL;
        CFStringRef chosenProtocol = NULL;
        err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);

        if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)
          chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0);

#ifdef USE_HTTP2
        if(chosenProtocol &&
           !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
          cf->conn->alpn = CURL_HTTP_VERSION_2;
        }
        else
#endif
        if(chosenProtocol &&
           !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) {
          cf->conn->alpn = CURL_HTTP_VERSION_1_1;
        }
        else
          infof(data, VTLS_INFOF_NO_ALPN);

        Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
                            BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);

        /* chosenProtocol is a reference to the string within alpnArr
           and does not need to be freed separately */
        if(alpnArr)
          CFRelease(alpnArr);
      }
    }
#endif

    return CURLE_OK;
  }
}