From 8a1267fe2fa12dcf80cb56409f9f6c3177be02e2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Kou=C5=99il?= Date: Tue, 19 Feb 2008 15:18:41 +0000 Subject: [PATCH] Added a call extracting a PEM string of client's certificate chain --- org.glite.security.gss/interface/glite_gss.h | 5 + org.glite.security.gss/src/glite_gss.c | 188 +++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) diff --git a/org.glite.security.gss/interface/glite_gss.h b/org.glite.security.gss/interface/glite_gss.h index 4b62c17..ae3971c 100644 --- a/org.glite.security.gss/interface/glite_gss.h +++ b/org.glite.security.gss/interface/glite_gss.h @@ -136,6 +136,11 @@ edg_wll_gss_get_client_conn(edg_wll_GssConnection *connection, edg_wll_GssPrincipal *principal, edg_wll_GssStatus* gss_code); +int +edg_wll_gss_get_client_pem(edg_wll_GssConnection *connection, + const char *my_cert_file, const char *my_key_file, + char **pem_string); + void edg_wll_gss_free_princ(edg_wll_GssPrincipal principal); diff --git a/org.glite.security.gss/src/glite_gss.c b/org.glite.security.gss/src/glite_gss.c index 165c2df..f325c14 100644 --- a/org.glite.security.gss/src/glite_gss.c +++ b/org.glite.security.gss/src/glite_gss.c @@ -18,6 +18,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "glite_gss.h" @@ -1213,6 +1218,189 @@ end: return ret; } +/* Beware, this call manipulates with environment variables and is not + thread-safe */ +static int +get_peer_cred(edg_wll_GssConnection *gss, const char *my_cert_file, + const char *my_key_file, STACK_OF(X509) **chain, + edg_wll_GssStatus* gss_code) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; + BIO *bio = NULL; + SSL_SESSION *session = NULL; + unsigned char int_buffer[4]; + long length; + int ret, index; + STACK_OF(X509) *cert_chain = NULL; + X509 *p_cert; + char *orig_cert = NULL, *orig_key = NULL; + + maj_stat = gss_export_sec_context(&min_stat, (gss_ctx_id_t *) &gss->context, + &buffer); + if (GSS_ERROR(maj_stat)) { + if (gss_code) { + gss_code->major_status = maj_stat; + gss_code->minor_status = min_stat; + } + return EDG_WLL_GSS_ERROR_GSS; + } + + /* The GSSAPI specs requires gss_export_sec_context() to destroy the + * context after exporting. So we have to resurrect the context here by + * importing from just generated buffer. gss_import_sec_context() must be + * able to read valid credential before it loads the exported context + * so we set the environment temporarily to point to the ones used by + * the server. + * */ + + orig_cert = getenv("X509_USER_CERT"); + orig_key = getenv("X509_USER_KEY"); + + if (my_cert_file) + setenv("X509_USER_CERT", my_cert_file, 1); + if (my_key_file) + setenv("X509_USER_KEY", my_key_file, 1); + + maj_stat = gss_import_sec_context(&min_stat, &buffer, + (gss_ctx_id_t *)&gss->context); + + if (orig_cert) + setenv("X509_USER_CERT", orig_cert, 1); + else + unsetenv("X509_USER_CERT"); + + if (orig_key) + setenv("X509_USER_KEY", orig_key, 1); + else + unsetenv("X509_USER_KEY"); + + if (GSS_ERROR(maj_stat)) { + if (gss_code) { + gss_code->major_status = maj_stat; + gss_code->minor_status = min_stat; + } + ret = EDG_WLL_GSS_ERROR_GSS; + goto end; + } + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + ret = ENOMEM; + goto end; + } + + /* Store exported context to memory, skipping the version number and and cred_usage fields */ + BIO_write(bio, buffer.value + 8 , buffer.length - 8); + + /* decode the session data in order to skip at the start of the cert chain */ + session = d2i_SSL_SESSION_bio(bio, NULL); + if (session == NULL) { + ret = EINVAL; + goto end; + } + SSL_SESSION_free(session); + + cert_chain = sk_X509_new_null(); + + BIO_read(bio, (char *) int_buffer, 4); + length = (((size_t) int_buffer[0]) << 24) & 0xffff; + length |= (((size_t) int_buffer[1]) << 16) & 0xffff; + length |= (((size_t) int_buffer[2]) << 8) & 0xffff; + length |= (((size_t) int_buffer[3]) ) & 0xffff; + + if (length == 0) { + ret = EINVAL; + goto end; + } + + for(index = 0; index < length; index++) { + p_cert = d2i_X509_bio(bio, NULL); + if (p_cert == NULL) { + ret = EINVAL; + sk_X509_pop_free(cert_chain, X509_free); + goto end; + } + + sk_X509_push(cert_chain, p_cert); + } + + *chain = cert_chain; + ret = 0; + +end: + gss_release_buffer(&min_stat, &buffer); + + return ret; +} + +int +edg_wll_gss_get_client_pem(edg_wll_GssConnection *connection, + const char *my_cert_file, const char *my_key_file, + char **pem_string) +{ + char *tmp = NULL; + STACK_OF(X509) *chain = NULL; + BIO *bio = NULL; + int ret, i; + size_t total_len, l; + + ret = get_peer_cred(connection, my_cert_file, my_key_file, &chain, NULL); + if (ret) + return ret; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) { + ret = ENOMEM; + goto end; + } + + for (i = 0; i < sk_X509_num(chain); i++) { + ret = PEM_write_bio_X509(bio, sk_X509_value(chain, i)); + if (ret <= 0) { + ret = EINVAL; + goto end; + } + } + + total_len = BIO_pending(bio); + if (total_len <= 0) { + ret = EINVAL; + goto end; + } + + tmp = malloc(total_len + 1); + if (tmp == NULL) { + ret = ENOMEM; + goto end; + } + + l = 0; + while (l < total_len) { + ret = BIO_read(bio, tmp+l, total_len-l); + if (ret <= 0) { + ret = EINVAL; + goto end; + } + l += ret; + } + + tmp[total_len] = '\0'; + *pem_string = tmp; + tmp = NULL; + + ret = 0; + +end: + sk_X509_pop_free(chain, X509_free); + if (bio) + BIO_free(bio); + if (tmp) + free(tmp); + + return ret; +} + void edg_wll_gss_free_princ(edg_wll_GssPrincipal principal) { -- 1.8.2.3