📄 ssl_utils.c
字号:
/* * ssl_utils.c * * Routines for interacting directly with SSL, X509 certificates, etc. */#include "myproxy_common.h" /* all needed headers included here */#define PEM_CALLBACK(func) func, NULL#define PEM_NO_CALLBACK NULL, NULL/********************************************************************** * * Constants * */#define PROXY_DEFAULT_LIFETIME -1L /* magic # for lifetime */ /* of signing cert *//********************************************************************** * * Internal data structures * */struct _ssl_credentials{ X509 *certificate; EVP_PKEY *private_key; STACK *certificate_chain; globus_gsi_proxy_handle_t proxy_req;};struct _ssl_proxy_restrictions{ /* 0 = unrestricted, 1 = limited */ int limited_proxy; /* Proxy lifetime in seconds, 0 means default, -1 means maximum */ long lifetime;};/********************************************************************** * * Internal variables. * *//* * Holder for pass phrase so callback function can find it. */static const char *_ssl_pass_phrase = NULL;/********************************************************************** * * Internal functions. * *//* * ssl_error_to_verror() * * Transfer an error description out of the ssl error handler to verror. */voidssl_error_to_verror(){ while (ERR_peek_error() != 0) { unsigned long error; ERR_STATE *error_state; const char *error_data; int error_number; /* Find data for last error */ error_state = ERR_get_state(); error_number = (error_state->bottom + 1) % ERR_NUM_ERRORS; error_data = error_state->err_data[error_number]; /* Pop error off of stack */ error = ERR_get_error(); /* Now add to verror state */ verror_put_string(ERR_error_string(error, NULL)); if (error_data != NULL) { verror_put_string(error_data); } } ERR_clear_error();}/* * bio_from_buffer() * * Given a buffer of length buffer_len, return a memory bio with the * contents of the buffer. * * Returns pointer to bio on success, NULL on error. */static BIO *bio_from_buffer(const unsigned char *buffer, int buffer_len){ BIO *bio = NULL; assert(buffer != NULL); bio = BIO_new(BIO_s_mem()); if (bio == NULL) { verror_put_string("Failed creating memory BIO"); ssl_error_to_verror(); goto error; } if (BIO_write(bio, (unsigned char *) buffer, buffer_len) == SSL_ERROR) { verror_put_string("Failed writing buffer to BIO"); ssl_error_to_verror(); BIO_free(bio); bio = NULL; goto error; } error: return bio;}/* * bio_to_buffer() * * Given a bio return the contents of the bio in a buffer. * pbuffer is set to point to the allocated buffer, and pbuffer_len * is filled in with the buffer length. Caller should free *pbuffer. * * Returns SSL_SUCCESS or SSL_ERROR. */static intbio_to_buffer(BIO *bio, unsigned char **pbuffer, int *pbuffer_len){ char *buffer = NULL; int buffer_len; int return_status = SSL_ERROR; assert(bio != NULL); buffer_len = BIO_pending(bio); buffer = malloc(buffer_len); if (buffer == NULL) { verror_put_string("Failed dumping BIO to buffer (malloc() failed)"); verror_put_errno(errno); goto error; } if (BIO_read(bio, buffer, buffer_len) == SSL_ERROR) { verror_put_string("Failed dumping BIO to buffer (BIO_read() failed)"); ssl_error_to_verror(); goto error; } /* Success */ *pbuffer = (unsigned char *)buffer; *pbuffer_len = buffer_len; return_status = SSL_SUCCESS; error: if (return_status == SSL_ERROR) { if (buffer != NULL) { free(buffer); } } return return_status;} /* * ssl_cert_chain_free() * * Free the given certificate chain and all it contents. */static voidssl_cert_chain_free(STACK *cert_chain){ if (cert_chain != NULL) { sk_pop_free(cert_chain, (void (*)(void *))X509_free); }}/* * ssl_credentials_free_contents() * * Free all the contents of the given credentials without freeing * the credentials structure itself. */static voidssl_credentials_free_contents(SSL_CREDENTIALS *creds){ if (creds != NULL) { if (creds->certificate != NULL) { X509_free(creds->certificate); } if (creds->private_key != NULL) { EVP_PKEY_free(creds->private_key); } if (creds->certificate_chain != NULL) { ssl_cert_chain_free(creds->certificate_chain); } }}static intcreds_from_bio(BIO *bio, SSL_CREDENTIALS **creds){ STACK *cert_chain = NULL; X509 *cert = NULL; unsigned char number_of_certs; int cert_index; int return_status = SSL_ERROR; if (BIO_read(bio, &number_of_certs, sizeof(number_of_certs)) == SSL_ERROR) { verror_put_string("Failed unpacking chain from buffer" "(reading number of certificates)"); ssl_error_to_verror(); return SSL_ERROR; } if (number_of_certs == 0) { verror_put_string("Failed unpacking chain from buffer" "(number of certificates is zero)"); ssl_error_to_verror(); return SSL_ERROR; } cert = d2i_X509_bio(bio, NULL /* make new cert */); if (cert == NULL) { verror_put_string("Failed unpacking chain from buffer" "(reading user's certificate)"); ssl_error_to_verror(); goto end; } /* Now read the certificate chain */ cert_chain = sk_new_null(); for (cert_index = 1; cert_index < number_of_certs; cert_index++) { X509 *x509; x509 = d2i_X509_bio(bio, NULL /* make new cert */); if (x509 == NULL) { verror_put_string("Failed unpacking chain from buffer" "(reading certificate)"); ssl_error_to_verror(); goto end; } if (sk_push(cert_chain, (char *) x509) == SSL_ERROR) { verror_put_string("Failed unpacking chain from buffer" "(building a new chain)"); ssl_error_to_verror(); X509_free(x509); goto end; } } *creds = ssl_credentials_new(); if (*creds == NULL) { verror_put_string("Failed unpacking chain from buffer" "(building a new chain)"); goto end; } (*creds)->certificate_chain = cert_chain; cert_chain = NULL; (*creds)->certificate = cert; cert = NULL; return_status = SSL_SUCCESS;end: if (cert) X509_free(cert); if (cert_chain) ssl_cert_chain_free(cert_chain); return return_status;}static intcreds_to_bio(SSL_CREDENTIALS *chain, BIO **bio){ unsigned char number_of_certs; BIO *output_bio = NULL; int index; int return_status = SSL_ERROR; output_bio = BIO_new(BIO_s_mem()); if (output_bio == NULL) { verror_put_string("BIO_new() failed"); ssl_error_to_verror(); return SSL_ERROR; } number_of_certs = sk_num(chain->certificate_chain) + 1; if (BIO_write(output_bio, &number_of_certs,sizeof(number_of_certs)) == SSL_ERROR) { verror_put_string("Failed dumping chain to buffer" "(BIO_write() failed)"); ssl_error_to_verror(); goto end; } if (i2d_X509_bio(output_bio, chain->certificate) == SSL_ERROR) { verror_put_string("Failed dumping chain to buffer " "(write of user's certificate failed)"); ssl_error_to_verror(); goto end; } for (index = 0; index < sk_num(chain->certificate_chain); index++) { X509 *cert; cert = (X509 *) sk_value(chain->certificate_chain, index); if (i2d_X509_bio(output_bio, cert) == SSL_ERROR) { verror_put_string("Failed dumping chain to buffer " "(write of cert chain failed)"); ssl_error_to_verror(); goto end; } } *bio = output_bio; output_bio = NULL; return_status = SSL_SUCCESS; end: if (output_bio) BIO_free(output_bio); return return_status;}/* * my_init() * * Do any needed initialization for these routines. * Should be called first. Can be called multiple times. */static voidmy_init(){ static int my_inited = 0; if (my_inited == 0) { my_inited = 1; /* Initialize the ssleay libraries */ SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); globus_module_activate(GLOBUS_GSI_PROXY_MODULE); globus_module_activate(GLOBUS_GSI_CREDENTIAL_MODULE); globus_module_activate(GLOBUS_GSI_SYSCONFIG_MODULE); globus_module_activate(GLOBUS_GSI_CERT_UTILS_MODULE); }} /* * my_pass_phrase_callback() * * Callback from PEM_read_PrivateKey() in ssl_load_user_key() * to return the passphrase stored in _ssl_pass_phrase. */static intmy_pass_phrase_callback(char *buffer, int buffer_len, int verify /* Ignored */, void *u){ /* SSL libs supply these, make sure they are reasonable */ assert(buffer != NULL); assert(buffer_len > 0); if (_ssl_pass_phrase == NULL) { strcpy(buffer, ""); } else { strncpy(buffer, _ssl_pass_phrase, buffer_len); buffer[buffer_len - 1] = '\0'; } return strlen(buffer);} /********************************************************************** * * API Functions * */voidssl_credentials_destroy(SSL_CREDENTIALS *creds){ my_init(); if (creds != NULL) { ssl_credentials_free_contents(creds); free(creds); }}intssl_proxy_file_destroy(const char *proxyfile){ FILE *fp; long offset, i; char zero = '\0'; struct stat s; int return_status = SSL_ERROR; assert(proxyfile != NULL); fp = fopen(proxyfile, "r+"); if (!fp) { verror_put_string("fopen(%s): %s\n", proxyfile, strerror(errno)); goto error; } /* Don't get fooled into zeroing out the wrong file via tricks with links and the like. */ if (fstat(fileno(fp), &s) < 0) { verror_put_string("fstat(%s): %s\n", proxyfile, strerror(errno)); goto error; } if (S_ISDIR(s.st_mode)) { verror_put_string("proxy file %s is a directory!\n", proxyfile); goto error; } if (!S_ISREG(s.st_mode)) { verror_put_string("proxy file %s is not a regular file!\n", proxyfile); goto error; } if (s.st_nlink != 1) { verror_put_string("proxy file %s has links!\n", proxyfile); goto error; } if (fseek(fp, 0L, SEEK_END) < 0) { verror_put_string("fseek(%s): %s\n", proxyfile, strerror(errno)); goto error; } offset = ftell(fp); if (offset < 0) { verror_put_string("ftell(%s): %s\n", proxyfile, strerror(errno)); goto error; } if (fseek(fp, 0L, SEEK_SET) < 0) { verror_put_string("fseek(%s): %s\n", proxyfile, strerror(errno)); goto error; } for (i=0; i < offset; i++) { if (fwrite(&zero, 1, 1, fp) != 1) { verror_put_string("fwrite(%s): %s\n", proxyfile, strerror(errno)); goto error; } } return_status = SSL_SUCCESS; error: if (fp) fclose(fp); if (unlink(proxyfile) < 0) { /* always try to unlink it, even on error */ verror_put_string("unlink: %s\n", strerror(errno)); return SSL_ERROR; } return return_status;} intssl_certificate_load_from_file(SSL_CREDENTIALS *creds, const char *path){ FILE *cert_file = NULL; X509 *cert = NULL; int return_status = SSL_ERROR; STACK *cert_chain = NULL; assert(creds != NULL); assert(path != NULL); my_init(); cert_file = fopen(path, "r"); if (cert_file == NULL) { verror_put_string("Error opening certificate file %s", path); verror_put_errno(errno); goto error; } if ((cert = PEM_read_X509(cert_file, NULL, PEM_NO_CALLBACK)) == NULL) { verror_put_string("Error reading certificate %s", path); ssl_error_to_verror(); goto error; } if (creds->certificate != NULL) { X509_free(creds->certificate); } creds->certificate = cert; /* Ok, now read the certificate chain */ /* Create empty stack */ cert_chain = sk_new_null(); while (1) { cert = NULL; if ((cert = PEM_read_X509(cert_file, NULL, PEM_NO_CALLBACK)) == NULL) { /* * If we just can't find a start line then we've reached EOF. */ if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE) { /* Just EOF, clear error and break out of loop */ ERR_clear_error(); break; } /* Actual error */ verror_put_string("Error parsing certificate chain"); ssl_error_to_verror(); goto error; } /* Add to chain */ if (sk_insert(cert_chain, (char *) cert, sk_num(cert_chain)) == SSL_ERROR) { verror_put_string("Error parsing certificate chain"); ssl_error_to_verror(); goto error; } } /* while(1) */ creds->certificate_chain = cert_chain; /* Success */ return_status = SSL_SUCCESS; error: if (cert_file != NULL) { fclose(cert_file); } return return_status;}intssl_private_key_load_from_file(SSL_CREDENTIALS *creds, const char *path, const char *pass_phrase, const char *pass_phrase_prompt){ FILE *key_file = NULL; EVP_PKEY *key = NULL; int return_status = SSL_ERROR; assert(creds != NULL); assert(path != NULL); my_init(); /* * Put pass phrase where the callback function can find it. */ _ssl_pass_phrase = pass_phrase; if (pass_phrase_prompt) EVP_set_pw_prompt((char *)pass_phrase_prompt); key_file = fopen(path, "r"); if (key_file == NULL) { verror_put_string("Error opening key file %s", path); verror_put_errno(errno); goto error; } if (PEM_read_PrivateKey(key_file, &(key), (pass_phrase_prompt) ? NULL : my_pass_phrase_callback, NULL) == NULL) { unsigned long error, reason;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -