~ubuntu-branches/ubuntu/maverick/curl/maverick

« back to all changes in this revision

Viewing changes to lib/ssluse.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2009-12-11 19:33:21 UTC
  • mfrom: (3.4.2 squeeze) (40.1.2 curl)
  • Revision ID: james.westby@ubuntu.com-20091211193321-tenukopudyznzbjj
* Merge with Debian testing.  Remaining changes:
  - Keep build deps in main:
    - Drop build dependencies: stunnel, libdb4.6-dev, libssh2-1-dev
    - Add build-dependency on openssh-server
    - Drop libssh2-1-dev from libcurl4-openssl-dev's Depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: ssluse.c,v 1.223 2009-05-04 21:57:14 bagder Exp $
 
21
 * $Id: ssluse.c,v 1.243 2009-10-14 02:32:27 gknauf Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
/*
63
63
#ifdef USE_OPENSSL
64
64
#include <openssl/rand.h>
65
65
#include <openssl/x509v3.h>
 
66
#include <openssl/dsa.h>
 
67
#include <openssl/dh.h>
66
68
#else
67
69
#include <rand.h>
68
70
#include <x509v3.h>
89
91
#if OPENSSL_VERSION_NUMBER >= 0x00907001L
90
92
/* ENGINE_load_private_key() takes four arguments */
91
93
#define HAVE_ENGINE_LOAD_FOUR_ARGS
 
94
#include <openssl/ui.h>
92
95
#else
93
96
/* ENGINE_load_private_key() takes three arguments */
94
97
#undef HAVE_ENGINE_LOAD_FOUR_ARGS
222
225
  /* If we get here, it means we need to seed the PRNG using a "silly"
223
226
     approach! */
224
227
#ifdef HAVE_RAND_SCREEN
225
 
  /* This one gets a random value by reading the currently shown screen */
226
 
  RAND_screen();
 
228
  /* if RAND_screen() is present, it was called during global init */
227
229
  nread = 100; /* just a value */
228
230
#else
229
231
  {
571
573
  if(!bio_out)
572
574
    return 1; /* alloc failed! */
573
575
 
574
 
  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_CPLUS_SPC);
 
576
  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
575
577
  BIO_get_mem_ptr(bio_out, &biomem);
576
578
 
577
579
  if((size_t)biomem->length < size)
633
635
  /* Lets get nice error messages */
634
636
  SSL_load_error_strings();
635
637
 
636
 
  /* Setup all the global SSL stuff */
 
638
  /* Init the global ciphers and digests */
637
639
  if(!SSLeay_add_ssl_algorithms())
638
640
    return 0;
639
641
 
 
642
  OpenSSL_add_all_algorithms();
 
643
 
 
644
#ifdef HAVE_RAND_SCREEN
 
645
  /* This one gets a random value by reading the currently shown screen.
 
646
     RAND_screen() is not thread-safe according to OpenSSL devs - although not
 
647
     mentioned in documentation. */
 
648
  RAND_screen();
 
649
#endif
 
650
 
640
651
  return 1;
641
652
}
642
653
 
650
661
  /* Free the SSL error strings */
651
662
  ERR_free_strings();
652
663
 
653
 
  /* EVP_cleanup() removes all ciphers and digests from the
654
 
     table. */
 
664
  /* EVP_cleanup() removes all ciphers and digests from the table. */
655
665
  EVP_cleanup();
656
666
 
657
667
#ifdef HAVE_ENGINE_cleanup
854
864
        /* timeout */
855
865
        failf(data, "SSL shutdown timeout");
856
866
        done = 1;
857
 
        break;
858
867
      }
859
868
      else {
860
869
        /* anything that gets here is fatally bad */
1047
1056
static CURLcode verifyhost(struct connectdata *conn,
1048
1057
                           X509 *server_cert)
1049
1058
{
1050
 
  bool matched = FALSE; /* no alternative match yet */
 
1059
  int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
 
1060
                       means mismatch */
1051
1061
  int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
1052
1062
  size_t addrlen = 0;
1053
1063
  struct SessionHandle *data = conn->data;
1084
1094
    numalts = sk_GENERAL_NAME_num(altnames);
1085
1095
 
1086
1096
    /* loop through all alternatives while none has matched */
1087
 
    for (i=0; (i<numalts) && !matched; i++) {
 
1097
    for (i=0; (i<numalts) && (matched != 1); i++) {
1088
1098
      /* get a handle to alternative name number i */
1089
1099
      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
1090
1100
 
1092
1102
      if(check->type == target) {
1093
1103
        /* get data and length */
1094
1104
        const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
1095
 
        size_t altlen;
 
1105
        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
1096
1106
 
1097
1107
        switch(target) {
1098
1108
        case GEN_DNS: /* name/pattern comparison */
1106
1116
             "I checked the 0.9.6 and 0.9.8 sources before my patch and
1107
1117
             it always 0-terminates an IA5String."
1108
1118
          */
1109
 
          if(cert_hostcheck(altptr, conn->host.name))
1110
 
            matched = TRUE;
 
1119
          if((altlen == strlen(altptr)) &&
 
1120
             /* if this isn't true, there was an embedded zero in the name
 
1121
                string and we cannot match it. */
 
1122
             cert_hostcheck(altptr, conn->host.name))
 
1123
            matched = 1;
 
1124
          else
 
1125
            matched = 0;
1111
1126
          break;
1112
1127
 
1113
1128
        case GEN_IPADD: /* IP address comparison */
1114
1129
          /* compare alternative IP address if the data chunk is the same size
1115
1130
             our server IP address is */
1116
 
          altlen = (size_t) ASN1_STRING_length(check->d.ia5);
1117
1131
          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
1118
 
            matched = TRUE;
 
1132
            matched = 1;
 
1133
          else
 
1134
            matched = 0;
1119
1135
          break;
1120
1136
        }
1121
1137
      }
1123
1139
    GENERAL_NAMES_free(altnames);
1124
1140
  }
1125
1141
 
1126
 
  if(matched)
 
1142
  if(matched == 1)
1127
1143
    /* an alternative name matched the server hostname */
1128
1144
    infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
 
1145
  else if(matched == 0) {
 
1146
    /* an alternative name field existed, but didn't match and then
 
1147
       we MUST fail */
 
1148
    infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
 
1149
    res = CURLE_PEER_FAILED_VERIFICATION;
 
1150
  }
1129
1151
  else {
1130
1152
    /* we have to look to the last occurence of a commonName in the
1131
1153
       distinguished one to get the most significant one. */
1138
1160
 
1139
1161
    X509_NAME *name = X509_get_subject_name(server_cert) ;
1140
1162
    if(name)
1141
 
      while((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0)
 
1163
      while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
1142
1164
        i=j;
1143
1165
 
1144
1166
    /* we have the name entry and we will now convert this to a string
1153
1175
         string manually to avoid the problem. This code can be made
1154
1176
         conditional in the future when OpenSSL has been fixed. Work-around
1155
1177
         brought by Alexis S. L. Carvalho. */
1156
 
      if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
1157
 
        j = ASN1_STRING_length(tmp);
1158
 
        if(j >= 0) {
1159
 
          peer_CN = OPENSSL_malloc(j+1);
1160
 
          if(peer_CN) {
1161
 
            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
1162
 
            peer_CN[j] = '\0';
 
1178
      if(tmp) {
 
1179
        if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
 
1180
          j = ASN1_STRING_length(tmp);
 
1181
          if(j >= 0) {
 
1182
            peer_CN = OPENSSL_malloc(j+1);
 
1183
            if(peer_CN) {
 
1184
              memcpy(peer_CN, ASN1_STRING_data(tmp), j);
 
1185
              peer_CN[j] = '\0';
 
1186
            }
1163
1187
          }
1164
1188
        }
 
1189
        else /* not a UTF8 name */
 
1190
          j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
 
1191
 
 
1192
        if(peer_CN && ((int)strlen((char *)peer_CN) != j)) {
 
1193
          /* there was a terminating zero before the end of string, this
 
1194
             cannot match and we return failure! */
 
1195
          failf(data, "SSL: illegal cert name field");
 
1196
          res = CURLE_PEER_FAILED_VERIFICATION;
 
1197
        }
1165
1198
      }
1166
 
      else /* not a UTF8 name */
1167
 
        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
1168
1199
    }
1169
1200
 
1170
1201
    if(peer_CN == nulstr)
1182
1213
    }
1183
1214
#endif /* CURL_DOES_CONVERSIONS */
1184
1215
 
1185
 
    if(!peer_CN) {
 
1216
    if(res)
 
1217
      /* error already detected, pass through */
 
1218
      ;
 
1219
    else if(!peer_CN) {
1186
1220
      failf(data,
1187
1221
            "SSL: unable to obtain common name from peer certificate");
1188
 
      return CURLE_PEER_FAILED_VERIFICATION;
 
1222
      res = CURLE_PEER_FAILED_VERIFICATION;
1189
1223
    }
1190
1224
    else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) {
1191
1225
      if(data->set.ssl.verifyhost > 1) {
1319
1353
#ifdef USE_SSLEAY
1320
1354
/* ====================================================== */
1321
1355
 
 
1356
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
 
1357
#  define use_sni(x)  sni = (x)
 
1358
#else
 
1359
#  define use_sni(x)  do { } while (0)
 
1360
#endif
 
1361
 
1322
1362
static CURLcode
1323
1363
ossl_connect_step1(struct connectdata *conn,
1324
1364
                   int sockindex)
1332
1372
  curl_socket_t sockfd = conn->sock[sockindex];
1333
1373
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1334
1374
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
 
1375
  bool sni;
1335
1376
#ifdef ENABLE_IPV6
1336
1377
  struct in6_addr addr;
1337
1378
#else
1350
1391
  case CURL_SSLVERSION_DEFAULT:
1351
1392
    /* we try to figure out version */
1352
1393
    req_method = SSLv23_client_method();
 
1394
    use_sni(TRUE);
1353
1395
    break;
1354
1396
  case CURL_SSLVERSION_TLSv1:
1355
1397
    req_method = TLSv1_client_method();
 
1398
    use_sni(TRUE);
1356
1399
    break;
1357
1400
  case CURL_SSLVERSION_SSLv2:
1358
1401
    req_method = SSLv2_client_method();
 
1402
    use_sni(FALSE);
1359
1403
    break;
1360
1404
  case CURL_SSLVERSION_SSLv3:
1361
1405
    req_method = SSLv3_client_method();
 
1406
    use_sni(FALSE);
1362
1407
    break;
1363
1408
  }
1364
1409
 
1491
1536
     * revocation */
1492
1537
    lookup=X509_STORE_add_lookup(connssl->ctx->cert_store,X509_LOOKUP_file());
1493
1538
    if ( !lookup ||
1494
 
         (X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE],
1495
 
                             X509_FILETYPE_PEM)!=1) ) {
 
1539
         (!X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE],
 
1540
                              X509_FILETYPE_PEM)) ) {
1496
1541
      failf(data,"error loading CRL file :\n"
1497
1542
            "  CRLfile: %s\n",
1498
1543
            data->set.str[STRING_SSL_CRLFILE]?
1545
1590
#ifdef ENABLE_IPV6
1546
1591
      (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
1547
1592
#endif
 
1593
      sni &&
1548
1594
      !SSL_set_tlsext_host_name(connssl->handle, conn->host.name))
1549
1595
    infof(data, "WARNING: failed to configure server name indication (SNI) "
1550
1596
          "TLS extension\n");
1563
1609
  }
1564
1610
 
1565
1611
  /* pass the raw socket into the SSL layers */
1566
 
  if(!SSL_set_fd(connssl->handle, sockfd)) {
 
1612
  if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
1567
1613
     failf(data, "SSL: SSL_set_fd failed: %s",
1568
1614
           ERR_error_string(ERR_get_error(),NULL));
1569
1615
     return CURLE_SSL_CONNECT_ERROR;
1689
1735
                                  size_t valuelen)
1690
1736
{
1691
1737
  struct curl_certinfo *ci = &data->info.certs;
1692
 
  char *outp;
 
1738
  char *output;
1693
1739
  struct curl_slist *nl;
1694
1740
  CURLcode res = CURLE_OK;
1695
1741
  size_t labellen = strlen(label);
1696
1742
  size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
1697
1743
 
1698
 
  outp = malloc(outlen);
1699
 
  if(!outp)
 
1744
  output = malloc(outlen);
 
1745
  if(!output)
1700
1746
    return CURLE_OUT_OF_MEMORY;
1701
1747
 
1702
1748
  /* sprintf the label and colon */
1703
 
  snprintf(outp, outlen, "%s:", label);
 
1749
  snprintf(output, outlen, "%s:", label);
1704
1750
 
1705
1751
  /* memcpy the value (it might not be zero terminated) */
1706
 
  memcpy(&outp[labellen+1], value, valuelen);
 
1752
  memcpy(&output[labellen+1], value, valuelen);
1707
1753
 
1708
1754
  /* zero terminate the output */
1709
 
  outp[labellen + 1 + valuelen] = 0;
 
1755
  output[labellen + 1 + valuelen] = 0;
1710
1756
 
1711
1757
  /* TODO: we should rather introduce an internal API that can do the
1712
1758
     equivalent of curl_slist_append but doesn't strdup() the given data as
1713
1759
     like in this place the extra malloc/free is totally pointless */
1714
 
  nl = curl_slist_append(ci->certinfo[certnum], outp);
 
1760
  nl = curl_slist_append(ci->certinfo[certnum], output);
1715
1761
  if(!nl) {
1716
1762
    curl_slist_free_all(ci->certinfo[certnum]);
1717
1763
    res = CURLE_OUT_OF_MEMORY;
1719
1765
  else
1720
1766
    ci->certinfo[certnum] = nl;
1721
1767
 
1722
 
  free(outp);
 
1768
  free(output);
1723
1769
 
1724
1770
  return res;
1725
1771
}
1786
1832
  for (i=0; i<sk_X509_EXTENSION_num(exts); i++) {
1787
1833
    ASN1_OBJECT *obj;
1788
1834
    X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
1789
 
    BIO *bio_out = BIO_new(BIO_s_mem());
1790
1835
    BUF_MEM *biomem;
1791
1836
    char buf[512];
1792
1837
    char *ptr=buf;
1793
1838
    char namebuf[128];
 
1839
    BIO *bio_out = BIO_new(BIO_s_mem());
 
1840
 
 
1841
    if(!bio_out)
 
1842
      return 1;
1794
1843
 
1795
1844
    obj = X509_EXTENSION_get_object(ext);
1796
1845
 
2251
2300
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2252
2301
  curl_socket_t sockfd = conn->sock[sockindex];
2253
2302
  long timeout_ms;
 
2303
  int what;
2254
2304
 
2255
2305
  if(ssl_connect_1==connssl->connecting_state) {
2256
2306
    /* Find out how much more time we're allowed */
2266
2316
      return retcode;
2267
2317
  }
2268
2318
 
2269
 
  timeout_ms = 0;
2270
2319
  while(ssl_connect_2 == connssl->connecting_state ||
2271
2320
        ssl_connect_2_reading == connssl->connecting_state ||
2272
2321
        ssl_connect_2_writing == connssl->connecting_state) {
2289
2338
      curl_socket_t readfd = ssl_connect_2_reading==
2290
2339
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
2291
2340
 
2292
 
      while(1) {
2293
 
        int what = Curl_socket_ready(readfd, writefd,
2294
 
                                     nonblocking?0:(int)timeout_ms);
2295
 
        if(what > 0)
2296
 
          /* readable or writable, go loop in the outer loop */
2297
 
          break;
2298
 
        else if(0 == what) {
2299
 
          if(nonblocking) {
2300
 
            *done = FALSE;
2301
 
            return CURLE_OK;
2302
 
          }
2303
 
          else {
2304
 
            /* timeout */
2305
 
            failf(data, "SSL connection timeout");
2306
 
            return CURLE_OPERATION_TIMEDOUT;
2307
 
          }
 
2341
      what = Curl_socket_ready(readfd, writefd,
 
2342
                               nonblocking?0:(int)timeout_ms);
 
2343
      if(what < 0) {
 
2344
        /* fatal error */
 
2345
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
 
2346
        return CURLE_SSL_CONNECT_ERROR;
 
2347
      }
 
2348
      else if(0 == what) {
 
2349
        if(nonblocking) {
 
2350
          *done = FALSE;
 
2351
          return CURLE_OK;
2308
2352
        }
2309
2353
        else {
2310
 
          /* anything that gets here is fatally bad */
2311
 
          failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2312
 
          return CURLE_SSL_CONNECT_ERROR;
 
2354
          /* timeout */
 
2355
          failf(data, "SSL connection timeout");
 
2356
          return CURLE_OPERATION_TIMEDOUT;
2313
2357
        }
2314
 
      } /* while()-loop for the select() */
 
2358
      }
 
2359
      /* socket is readable or writable */
2315
2360
    }
2316
2361
 
2317
 
    /* get the timeout from step2 to avoid computing it twice. */
2318
2362
    retcode = ossl_connect_step2(conn, sockindex);
2319
2363
    if(retcode)
2320
2364
      return retcode;