curl NSS -12286 error in TLS handshake

14,790

Solution 1

The very first thing I notice, you're doing:

rv=curl_easy_setopt (ch, CURLOPT_CAPATH, "./cacert.pem" );

needs to specify a "string naming a directory holding multiple CA certificates to verify the peer with". From the man page. You'll probably want "/etc/tls/certs/"

In addition, it would appear the line:

rv=curl_easy_setopt(ch,CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); 

is doing nothing. I say this because, again, from the man page, "This option does only function for libcurl powered by OpenSSL". I say this because, your error log has "NSS error"

My experience with working with ssl is only with openssl. I found the command line function openssl s_client to be helpful. That being said, it is very easy to miss configure your setup. Many functions and command line options will try to work with even the craziest input, leading to red herring errors.

Edit: My attempt at your program completes with success.

#include <stdio.h>
#include <curl/curl.h>

int main(void)
{
    CURL * ch;
    CURLcode rv;
    rv=curl_global_init(CURL_GLOBAL_ALL);
    ch=curl_easy_init();
    rv=curl_easy_setopt(ch, CURLOPT_VERBOSE, 1L);
    rv=curl_easy_setopt(ch, CURLOPT_CAPATH, "/etc/ssl/certs");
    rv=curl_easy_setopt(ch, CURLOPT_URL, "https://");
    rv=curl_easy_perform(ch);
    if (rv==CURLE_OK) {
        printf("*** transfer succeeded ***\n");
    }
    else {
        printf("*** transfer failed ***\n");
    }
    curl_easy_cleanup(ch);
    curl_global_cleanup();
    return rv;
}

Solution 2

Ran into this in PHP. I ran curl on the command line with -v and found the NSS -12286 error.

Turns out that the remote server and curl did not have a common cypher (nss error codes). We added a cypher to the curl object like so:

curl_setopt($oCurl, CURLOPT_SSL_CIPHER_LIST, 'rsa_rc4_128_sha');
Share:
14,790
user1495372
Author by

user1495372

Updated on June 04, 2022

Comments

  • user1495372
    user1495372 almost 2 years

    I am getting NSS -12286 error while trying to load the https page using the ca certificate using cacertinpem.c curl c code. i am using cacert.pem file in the code alog with path. but same thing is working when i try using curl -v "https://sampleserve.com:443",in this case ssl is taking default ca path as "/etc/tls/certs/ca.budle.crt"

    But this c code is not working for both default ca location and external path selection of ca aswell.

    What is the reason for this error(NSS -12286).

    Error:
    * About to connect() to fiservices.sterlingbankng.com port 443 (#0)
    *   Trying 1.1.1.1... * Connection timed out
    *   Trying 1.1.1.2... * connected
    * Connected to fiservices.sterlingbankng.com (1.1.1.2) port 443 (#0)
    * Initializing NSS with certpath: /etc/pki/nssdb
    *   CAfile: ./cacert.pem   CApath: ./cacert.pem
    * NSS error -12286
    * Error in TLS handshake, trying SSLv3...
    
    GET /CanFI/ HTTP/1.1
    Host: sampleserver.com
    Accept: */*
    
    * Connection died, retrying a fresh connect
    * Closing connection #0
    * Issue another request to this URL: 'https://sampleserver.com'
    * About to connect() to sampleserver.com port 443 (#0)
    *   Trying 1.1.1.1... * Connection timed out
    *   Trying 1.1.1.2... * connected
    * Connected to sampleserver.com (1.1.1.2) port 443 (#0)
    * TLS disabled due to previous handshake failure
    *   CAfile: ./cacert.pem
      CApath: ./cacert.pem
    * NSS error -12286
    * Closing connection #0
    * SSL connect error
    

    Sample code:

    size_t writefunction( void *ptr, size_t size, size_t nmemb, void *stream)
    {
      fwrite(ptr,size,nmemb,stream);              
    
      return(nmemb*size);                   
    }
    
    static CURLcode sslctx_function(CURL * curl, void * sslctx, void * parm)
    {
    
      X509_STORE * store;
    
      X509 * cert=NULL;   
    
      BIO * bio;                             
    
      char * mypem = "-----BEGIN CERTIFICATE-----\n"\     "-----END CERTIFICATE-----\n";  //public certificate    
    
    }     
    
    int main(void)    
    {
    
      CURL * ch;
    
      CURLcode rv;
    
      rv=curl_global_init(CURL_GLOBAL_ALL);
    
      ch=curl_easy_init();
    
      rv=curl_easy_setopt(ch,CURLOPT_VERBOSE, 1L);
    
      rv=curl_easy_setopt(ch,CURLOPT_HEADER, 0L);
    
      rv=curl_easy_setopt(ch,CURLOPT_NOPROGRESS, 1L);
    
      rv=curl_easy_setopt(ch,CURLOPT_NOSIGNAL, 1L);
    
      rv=curl_easy_setopt(ch,CURLOPT_WRITEFUNCTION, *writefunction);
    
      rv=curl_easy_setopt(ch,CURLOPT_WRITEDATA, stdout);
    
      rv=curl_easy_setopt(ch,CURLOPT_HEADERFUNCTION, *writefunction);
    
      rv=curl_easy_setopt(ch,CURLOPT_WRITEHEADER, stderr);
    
      rv=curl_easy_setopt(ch,CURLOPT_SSLCERTTYPE,"PEM");  
    
      rv=curl_easy_setopt (ch, CURLOPT_CAPATH, "./cacert.pem" );  
    
      rv=curl_easy_setopt (ch, CURLOPT_CAINFO, "./cacert.pem" ); 
    
      rv=curl_easy_setopt(ch,CURLOPT_SSL_VERIFYPEER,1L); 
    
      rv=curl_easy_setopt(ch, CURLOPT_URL, "https://");   
    
      rv=curl_easy_perform(ch);           
    
      if (rv==CURLE_OK)             
    
        printf("*** transfer succeeded ***\n"); 
    
      else                   
    
        printf("*** transfer failed ***\n"); 
    
      rv=curl_easy_setopt(ch,CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); 
    
      rv=curl_easy_perform(ch);              
    
      if (rv==CURLE_OK)             
    
        printf("*** transfer succeeded ***\n");               
      else             
    
        printf("*** transfer failed ***\n");               
    
      curl_easy_cleanup(ch);  
    
      curl_global_cleanup();  
    
      return rv;               
    }
    

    Thanks

  • user1495372
    user1495372 almost 11 years
    Thanks..As you have mentioned above i have tried giving complete path of CA certificate and removing ctx option aswell.But still error remains same.And also i have tried using "openssl s_client -verify 0 -connect ip:port" using command ,i could able to get server public certificate ,below are the some part of output log.openssl s_client -verify 0 -connect ip:port verify depth is 0 CONNECTED(00000003) depth=3 C = US, O = "VeriSign, Inc.", OU = Class 3 Public Primary Certification Authority verify return:1 3 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary C