📄 ssluse.c
字号:
/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id: ssluse.c,v 1.84 2003/10/23 07:44:55 bagder Exp $ ***************************************************************************//* * The original SSL code for curl was written by * Linas Vepstas <linas@linas.org> and Sampo Kellomaki <sampo@iki.fi> */#include "setup.h"#include <string.h>#include <stdlib.h>#include <ctype.h>#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#include "urldata.h"#include "sendf.h"#include "formdata.h" /* for the boundary function */#include "url.h" /* for the ssl config check function */#include "inet_pton.h"#ifdef USE_SSLEAY#include <openssl/rand.h>#include <openssl/x509v3.h>/* The last #include file should be: */#ifdef CURLDEBUG#include "memdebug.h"#endif#if OPENSSL_VERSION_NUMBER >= 0x0090581fL#define HAVE_SSL_GET1_SESSION 1#else#undef HAVE_SSL_GET1_SESSION#endif#if OPENSSL_VERSION_NUMBER >= 0x00904100L#define HAVE_USERDATA_IN_PWD_CALLBACK 1#else#undef HAVE_USERDATA_IN_PWD_CALLBACK#endif#if OPENSSL_VERSION_NUMBER >= 0x00907001L/* ENGINE_load_private_key() takes four arguments */#define HAVE_ENGINE_LOAD_FOUR_ARGS#else/* ENGINE_load_private_key() takes three arguments */#undef HAVE_ENGINE_LOAD_FOUR_ARGS#endif#ifndef HAVE_USERDATA_IN_PWD_CALLBACKstatic char global_passwd[64];#endifstatic int passwd_callback(char *buf, int num, int verify#if HAVE_USERDATA_IN_PWD_CALLBACK /* This was introduced in 0.9.4, we can set this using SSL_CTX_set_default_passwd_cb_userdata() */ , void *global_passwd#endif ){ if(verify) fprintf(stderr, "%s\n", buf); else { if(num > (int)strlen((char *)global_passwd)) { strcpy(buf, global_passwd); return strlen(buf); } } return 0;}staticbool seed_enough(int nread){#ifdef HAVE_RAND_STATUS nread = 0; /* to prevent compiler warnings */ /* only available in OpenSSL 0.9.5a and later */ if(RAND_status()) return TRUE;#else if(nread > 500) /* this is a very silly decision to make */ return TRUE;#endif return FALSE; /* not enough */}staticint random_the_seed(struct SessionHandle *data){ char *buf = data->state.buffer; /* point to the big buffer */ int nread=0; /* Q: should we add support for a random file name as a libcurl option? A: Yes, it is here */#ifndef RANDOM_FILE /* if RANDOM_FILE isn't defined, we only perform this if an option tells us to! */ if(data->set.ssl.random_file)#define RANDOM_FILE "" /* doesn't matter won't be used */#endif { /* let the option override the define */ nread += RAND_load_file((data->set.ssl.random_file? data->set.ssl.random_file:RANDOM_FILE), 16384); if(seed_enough(nread)) return nread; }#if defined(HAVE_RAND_EGD) /* only available in OpenSSL 0.9.5 and later */ /* EGD_SOCKET is set at configure time or not at all */#ifndef EGD_SOCKET /* If we don't have the define set, we only do this if the egd-option is set */ if(data->set.ssl.egdsocket)#define EGD_SOCKET "" /* doesn't matter won't be used */#endif { /* If there's an option and a define, the option overrides the define */ int ret = RAND_egd(data->set.ssl.egdsocket? data->set.ssl.egdsocket:EGD_SOCKET); if(-1 != ret) { nread += ret; if(seed_enough(nread)) return nread; } }#endif /* If we get here, it means we need to seed the PRNG using a "silly" approach! */#ifdef HAVE_RAND_SCREEN /* This one gets a random value by reading the currently shown screen */ RAND_screen(); nread = 100; /* just a value */#else { int len; char *area; /* Changed call to RAND_seed to use the underlying RAND_add implementation * directly. Do this in a loop, with the amount of additional entropy * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes * of a 7-bit ascii set. -- Richard Gorton, March 11 2003. */ do { area = Curl_FormBoundary(); if(!area) return 3; /* out of memory */ len = strlen(area); RAND_add(area, len, (len >> 1)); free(area); /* now remove the random junk */ } while (!RAND_status()); }#endif /* generates a default path for the random seed file */ buf[0]=0; /* blank it first */ RAND_file_name(buf, BUFSIZE); if(buf[0]) { /* we got a file name to try */ nread += RAND_load_file(buf, 16384); if(seed_enough(nread)) return nread; } infof(data, "libcurl is now using a weak random seed!\n"); return nread;}#ifndef SSL_FILETYPE_ENGINE#define SSL_FILETYPE_ENGINE 42#endifstatic int do_file_type(const char *type){ if(!type || !type[0]) return SSL_FILETYPE_PEM; if(curl_strequal(type, "PEM")) return SSL_FILETYPE_PEM; if(curl_strequal(type, "DER")) return SSL_FILETYPE_ASN1; if(curl_strequal(type, "ENG")) return SSL_FILETYPE_ENGINE; return -1;}staticint cert_stuff(struct connectdata *conn, char *cert_file, const char *cert_type, char *key_file, const char *key_type){ struct SessionHandle *data = conn->data; int file_type; if(cert_file != NULL) { SSL *ssl; X509 *x509; if(data->set.key_passwd) {#ifndef HAVE_USERDATA_IN_PWD_CALLBACK /* * If password has been given, we store that in the global * area (*shudder*) for a while: */ strcpy(global_passwd, data->set.key_passwd);#else /* * We set the password in the callback userdata */ SSL_CTX_set_default_passwd_cb_userdata(conn->ssl.ctx, data->set.key_passwd);#endif /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(conn->ssl.ctx, passwd_callback); } file_type = do_file_type(cert_type); switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ if(SSL_CTX_use_certificate_chain_file(conn->ssl.ctx, cert_file) != 1) { failf(data, "unable to set certificate file (wrong password?)"); return 0; } break; case SSL_FILETYPE_ASN1: /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but we use the case above for PEM so this can only be performed with ASN1 files. */ if(SSL_CTX_use_certificate_file(conn->ssl.ctx, cert_file, file_type) != 1) { failf(data, "unable to set certificate file (wrong password?)"); return 0; } break; case SSL_FILETYPE_ENGINE: failf(data, "file type ENG for certificate not implemented"); return 0; default: failf(data, "not supported file type '%s' for certificate", cert_type); return 0; } file_type = do_file_type(key_type); switch(file_type) { case SSL_FILETYPE_PEM: if(key_file == NULL) /* cert & key can only be in PEM case in the same file */ key_file=cert_file; case SSL_FILETYPE_ASN1: if(SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, key_file, file_type) != 1) { failf(data, "unable to set private key file: '%s' type %s\n", key_file, key_type?key_type:"PEM"); return 0; } break; case SSL_FILETYPE_ENGINE:#ifdef HAVE_OPENSSL_ENGINE_H { /* XXXX still needs some work */ EVP_PKEY *priv_key = NULL; if(conn && conn->data && conn->data->engine) {#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_METHOD *ui_method = UI_OpenSSL();#endif if(!key_file || !key_file[0]) { failf(data, "no key set to load from crypto engine\n"); return 0; } priv_key = ENGINE_load_private_key(conn->data->engine,key_file,#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS ui_method,#endif data->set.key_passwd); if(!priv_key) { failf(data, "failed to load private key from crypto engine\n"); return 0; } if(SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) { failf(data, "unable to set private key\n"); EVP_PKEY_free(priv_key); return 0; } EVP_PKEY_free(priv_key); /* we don't need the handle any more... */ } else { failf(data, "crypto engine not set, can't load private key\n"); return 0; } }#else failf(data, "file type ENG for private key not supported\n"); return 0;#endif break; default: failf(data, "not supported file type for private key\n"); return 0; } ssl=SSL_new(conn->ssl.ctx); x509=SSL_get_certificate(ssl); /* This version was provided by Evan Jordan and is supposed to not leak memory as the previous version: */ if(x509 != NULL) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl)); EVP_PKEY_free(pktmp); } SSL_free(ssl); /* If we are using DSA, we can copy the parameters from * the private key */ /* Now we know that a key and cert have been set against * the SSL context */ if(!SSL_CTX_check_private_key(conn->ssl.ctx)) { failf(data, "Private key does not match the certificate public key"); return(0); }#ifndef HAVE_USERDATA_IN_PWD_CALLBACK /* erase it now */ memset(global_passwd, 0, sizeof(global_passwd));#endif } return(1);}staticint cert_verify_callback(int ok, X509_STORE_CTX *ctx){ X509 *err_cert; char buf[256]; err_cert=X509_STORE_CTX_get_current_cert(ctx); X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256); return ok;}#endif#ifdef USE_SSLEAY/* "global" init done? */static int init_ssl=0;/* we have the "SSL is seeded" boolean global for the application to prevent multiple time-consuming seedings in vain */static bool ssl_seeded = FALSE;#endif/* Global init */void Curl_SSL_init(void){#ifdef USE_SSLEAY /* make sure this is only done once */ if(0 != init_ssl) return; init_ssl++; /* never again */#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES ENGINE_load_builtin_engines();#endif /* Lets get nice error messages */ SSL_load_error_strings();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -