From: Daniel KouĊ™il Date: Mon, 12 Dec 2011 12:51:35 +0000 (+0000) Subject: import of VOMS routines to handle grid-specific stuff X-Git-Tag: merge_30_head_take2_after~11 X-Git-Url: http://scientific.zcu.cz/git/?a=commitdiff_plain;h=bffb64495462391950cca745ebfa2aeec4f0ca5f;p=jra1mw.git import of VOMS routines to handle grid-specific stuff --- diff --git a/emi.canl.canl-c/src/proxy/config.h b/emi.canl.canl-c/src/proxy/config.h new file mode 100644 index 0000000..5841d88 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/config.h @@ -0,0 +1,14 @@ +#if defined(__GNUC__) +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define UNUSED(z) z __attribute__ ((unused)) +#else +#define UNUSED(z) z +#endif +#define PRIVATE __attribute__ ((visibility ("hidden"))) +#define PUBLIC __attribute__ ((visibility ("default"))) +#else +#define UNUSED(z) z +#define PRIVATE +#define PUBLIC +#endif + diff --git a/emi.canl.canl-c/src/proxy/doio.c b/emi.canl.canl-c/src/proxy/doio.c new file mode 100644 index 0000000..671c0f4 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/doio.c @@ -0,0 +1,72 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ + +#include "config.h" + +#include +#include +#include + +char *vsnprintf_wrap(const char *format, va_list v) +{ + va_list w; + + va_copy(w,v);; + char *str = NULL; + int plen = 0; + + plen = vsnprintf(str, 0, format, v); + + if (plen > 0) { + str = (char *)malloc(plen+1); + if (str) { + (void)vsnprintf(str, plen+1, format, w); + va_end(w); + } + } + + return str; +} + +char *snprintf_wrap(const char *format, ...) +{ + va_list v; + char *str = NULL; + + va_start(v, format); + str = vsnprintf_wrap(format, v); + va_end(v); + + return str; +} + +int fileexists(const char *file) +{ + FILE *f = fopen(file, "r"); + close(f); + + return f != NULL; +} + diff --git a/emi.canl.canl-c/src/proxy/doio.h b/emi.canl.canl-c/src/proxy/doio.h new file mode 100644 index 0000000..de1d965 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/doio.h @@ -0,0 +1,34 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ + +#ifndef VOMS_DOIO_H +#define VOMS_DOIO_H + +#include + +extern char *snprintf_wrap(const char *format, ...); +extern char *vsnprintf_wrap(const char *format, va_list v); +extern int fileexists(const char*); +#endif diff --git a/emi.canl.canl-c/src/proxy/evaluate.c b/emi.canl.canl-c/src/proxy/evaluate.c new file mode 100644 index 0000000..09b8ba4 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/evaluate.c @@ -0,0 +1,400 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" +#include +#include "parsertypes.h" +#include "doio.h" +#include "listfunc.h" +#include "normalize.h" + +#include +#include +#include + +static char *gethash(X509 *cert, char *hash); +static int find_policy(struct policy **policies, X509 *cert, int current); +static int evaluate_match_namespace(char *pattern, char *subject, int type); +static int evaluate_match_signing(char *pattern, char *subject, int type); +static int restriction_evaluate_policy(X509 *cert, struct policy *policy); +static int evaluate_cert(X509 *cert, struct policy **namespaces); +static int restriction_evaluate_namespace(STACK_OF(X509) *chain, struct policy **namespaces); +static int restriction_evaluate_signing(STACK_OF(X509) *chain, struct policy **signings); +static FILE *open_from_dir(char *path, char *file); + +extern int signinglex_init (void** scanner); +extern void signingset_in (FILE * in_str ,void *yyscanner ); +extern int signinglex_destroy (void* yyscanner ); +extern int signingparse(struct policy ***policies, void *scanner); + +extern int namespaceslex_init (void** scanner); +extern void namespacesset_in (FILE * in_str ,void *yyscanner ); +extern int namespaceslex_destroy (void* yyscanner ); +extern int namespacesparse(struct policy ***policies, void *scanner); + +static int find_policy(struct policy **policies, X509 *cert, int current) +{ + int i = (current == -1 ? 0 : current + 1); + + char hash[EVP_MAX_MD_SIZE+1]; + + if (!policies || !(policies[0]) || !cert) + return -1; + + while (policies[i]) { + if (policies[i]->self) { + if (!strcmp(gethash(cert, hash), policies[i]->caname)) + return i; + } + else { + char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + int ret = strcmp(issuer, policies[i]->caname); + OPENSSL_free(issuer); + + if (!ret) + return i; + } + i++; + } + + /* If code reaches here, no match was found. */ + return -1; +} + +static char *gethash(X509 *cert, char *hash) +{ + unsigned long hashvalue = X509_subject_name_hash(cert); + sprintf(hash, "%08lx", hashvalue); + return hash; +} + +static int evaluate_match_namespace(char *pattern, char *subject, int type) +{ + regex_t compiled; + regmatch_t match[1]; + int success = SUCCESS_UNDECIDED; + char *patterntmp = normalize(pattern); + char *subjecttmp = normalize(subject); + + if (!regcomp(&compiled, patterntmp, REG_NOSUB)) { + if (!regexec(&compiled, subjecttmp, 0, match, 0)) { + /* matched */ + if (type) + success = SUCCESS_PERMIT; + else + success = SUCCESS_DENY; + } + } + + regfree(&compiled); + free(patterntmp); + free(subjecttmp); + + return success; +} + +static int evaluate_match_signing(char *pattern, char *subject, int type) +{ + int success = SUCCESS_UNDECIDED; + int len = 0; + int compare; + char *patterntmp = normalize(pattern); + char *subjecttmp = normalize(subject); + + if (!pattern || !subject) + return success; + + len = strlen(pattern); + + if (pattern[len-1] == '*') + compare = strncmp(patterntmp, subjecttmp, len-1); + else + compare = strcmp(patterntmp, subjecttmp); + + free(patterntmp); + free(subjecttmp); + + if (!compare) { + if (type) + return SUCCESS_PERMIT; + else + return SUCCESS_DENY; + } + + return success; +} + +static int restriction_evaluate_policy(X509 *cert, struct policy *policy) +{ + int success = SUCCESS_UNDECIDED; + char *subject = NULL; + + struct condition **cond = NULL; + int condindex = 0; + int subjindex = 0; + + if (!policy || !cert || !policy->conds) + return success; + + subject = X509_NAME_oneline(X509_get_subject_name(cert), 0 ,0); + if (!subject) + return success; + + cond = policy->conds; + + while (cond[condindex]) { + if (cond[condindex]->subjects) { + char **subjects = cond[condindex]->subjects; + int tempsuccess; + + while (subjects[subjindex]) { + if (policy->type == TYPE_NAMESPACE) + tempsuccess = evaluate_match_namespace(subjects[subjindex], + subject, + cond[condindex]->positive); + else + tempsuccess = evaluate_match_signing(subjects[subjindex], + subject, + cond[condindex]->positive); + + + if (tempsuccess != SUCCESS_UNDECIDED) + success = tempsuccess; + + if (success == SUCCESS_DENY) + goto end; + + subjindex++; + } + } + condindex++; + } + +end: + OPENSSL_free(subject); + return success; +} + +static int isselfsigned(X509*cert) +{ + return !X509_NAME_cmp(X509_get_subject_name(cert), + X509_get_issuer_name(cert)); + +} + +static int evaluate_cert(X509 *cert, struct policy **namespaces) +{ + int result = SUCCESS_UNDECIDED; + int policyindex = -1, + currentindex = -1; + + /* self-signed certificates always pass */ + if (isselfsigned(cert)) { + char *subject = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + OPENSSL_free(subject); + return SUCCESS_PERMIT; + } + while ((policyindex = find_policy(namespaces, cert, currentindex)) != -1) { + struct policy *policy = namespaces[policyindex]; + + result = restriction_evaluate_policy(cert, policy); + + if (result != SUCCESS_UNDECIDED) + break; + currentindex = policyindex; + } + + return result; +} + +static int restriction_evaluate_namespace(STACK_OF(X509) *chain, struct policy **namespaces) +{ + int size = sk_X509_num(chain); + int i = 0; + int result = 0; + int start = 0, end = 0; + int step = 0; + + if (size > 1 && isselfsigned(sk_X509_value(chain,0))) { + /* reverse certificate ordering. Reverse direction of visit */ + + start = size - 1; + end = -1; + step = -1; + } + else { + /* right order */ + start = 0; + end = size; + step = 1; + } + + for (i = start; i != end; i += step) { + int j; + X509 *cert = sk_X509_value(chain, i); + + for (j = i; j >= 0; j--) { + result = evaluate_cert(cert, namespaces); + + if (result != SUCCESS_UNDECIDED) + break; + } + } + + if (result == SUCCESS_UNDECIDED) { + result = SUCCESS_PERMIT; + } + + return result; +} + +static int restriction_evaluate_signing(STACK_OF(X509) *chain, struct policy **signings) +{ + int size = sk_X509_num(chain); + int i = 0; + int result = 0; + + for (i = 0; i < size; i++) { + X509 *cert = sk_X509_value(chain, i); + + result = evaluate_cert(cert, signings); + + if (result != SUCCESS_UNDECIDED) + break; + } + + if (result == SUCCESS_UNDECIDED) + result = SUCCESS_DENY; + + return result; +} + +int PRIVATE restriction_evaluate(STACK_OF(X509) *chain, struct policy **namespaces, + struct policy **signings) +{ + int result = 0; + + result = restriction_evaluate_namespace(chain, namespaces); + + if (result == SUCCESS_UNDECIDED) { + result = restriction_evaluate_signing(chain, signings); + } + return result; +} + +static void free_condition(struct condition *cond) +{ + free(cond->original); + free(cond->subjects); + free(cond); +} + +static void free_policy(struct policy *pol) +{ + free(pol->caname); + + listfree((char**)(pol->conds), (freefn)free_condition); + free(pol); +} + +void PRIVATE voms_free_policies(struct policy **policies) +{ + listfree((char**)policies, (freefn)free_policy); +} + +static FILE *open_from_dir(char *path, char *filename) +{ + char *realpath=snprintf_wrap("%s%s", path, filename); + FILE *file = NULL; + + file = fopen(realpath, "rb"); + + free(realpath); + + return file; +} + + +void PRIVATE read_pathrestriction(STACK_OF(X509) *chain, char *path, + struct policy ***names, + struct policy ***signs) +{ + int size = sk_X509_num(chain); + char hashed[9]; + char *hash; + char signing[25] = "/XXXXXXXX.signing_policy"; + char namespace[21] = "/XXXXXXXX.namespaces"; + int i = 0, j = 0; + FILE *file = NULL; + + for (i = 0; i < size; i++) { + X509 *cert = sk_X509_value(chain, i); + hash = gethash(cert, hashed); + + /* Determine file names */ + strncpy(signing + 1, hash, 8); + strncpy(namespace + 1, hash, 8); + + file = open_from_dir(path, signing); + if (file) { + void *scanner = NULL; + + signinglex_init(&scanner); + signingset_in(file, scanner); + (void)signingparse(signs, scanner); + signinglex_destroy(scanner); + fclose(file); + } + + j = 0; + if (*signs) { + while ((*signs)[j]) { + if ((*signs)[j]->self) + (*signs)[j]->caname = strdup(hash); + j++; + } + } + + file = open_from_dir(path, namespace); + if (file) { + void *scanner = NULL; + + namespaceslex_init(&scanner); + namespacesset_in(file, scanner); + (void)namespacesparse(names, scanner); + namespaceslex_destroy(scanner); + fclose(file); + } + + if (*names) { + int j = 0; + + while ((*names)[j]) { + if ((*names)[j]->self) + (*names)[j]->caname = strdup(hash); + j++; + } + } + } +} diff --git a/emi.canl.canl-c/src/proxy/list.c b/emi.canl.canl-c/src/proxy/list.c new file mode 100644 index 0000000..27b8246 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/list.c @@ -0,0 +1,69 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" + +#include +#include + +char **listadd(char **vect, char *data) +{ + int i = 0; + char **newvect; + + if (!data) + return vect; + + if (vect) + while (vect[i++]) ; + else + i=1; + + if ((newvect = (char **)malloc((i+1)*sizeof(char *)))) { + if (vect) { + memcpy(newvect, vect, (sizeof(char*)*(i-1))); + newvect[i-1] = data; + newvect[i] = NULL; + free(vect); + } + else { + newvect[0] = data; + newvect[1] = NULL; + } + return newvect; + } + return NULL; +} + +void listfree(char **vect, void (*f)(void *)) +{ + char **tmp = vect; + + if (tmp) { + int i = 0; + while (tmp[i]) + f(tmp[i++]); + free(vect); + } +} diff --git a/emi.canl.canl-c/src/proxy/listfunc.h b/emi.canl.canl-c/src/proxy/listfunc.h new file mode 100644 index 0000000..bfc894f --- /dev/null +++ b/emi.canl.canl-c/src/proxy/listfunc.h @@ -0,0 +1,33 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#ifndef VOMS_LISTFUNC_H +#define VOMS_LISTFUNC_H +#include + +typedef void (*freefn)(void *); + +extern char **listadd(char **vect, char *data); +extern void listfree(char **vect, freefn f); +#endif diff --git a/emi.canl.canl-c/src/proxy/myproxycertinfo.h b/emi.canl.canl-c/src/proxy/myproxycertinfo.h new file mode 100644 index 0000000..2840971 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/myproxycertinfo.h @@ -0,0 +1,131 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * Valerio Venturi - valerio.venturi@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#ifndef VOMS_PROXYCERTINFO_H +#define VOMS_PROXYCERTINFO_H + +#include +#include +#include + +/* predefined policy language */ +#define IMPERSONATION_PROXY_OID "1.3.6.1.5.5.7.21.1" +#define IMPERSONATION_PROXY_SN "IMPERSONATION_PROXY" +#define IMPERSONATION_PROXY_LN "GSI impersonation proxy" + +#define INDEPENDENT_PROXY_OID "1.3.6.1.5.5.7.21.2" +#define INDEPENDENT_PROXY_SN "INDEPENDENT_PROXY" +#define INDEPENDENT_PROXY_LN "GSI independent proxy" + +/* generic policy language */ +#define GLOBUS_GSI_PROXY_GENERIC_POLICY_OID "1.3.6.1.4.1.3536.1.1.1.8" + +#define LIMITED_PROXY_OID "1.3.6.1.4.1.3536.1.1.1.9" +#define LIMITED_PROXY_SN "LIMITED_PROXY" +#define LIMITED_PROXY_LN "GSI limited proxy" + +#define PROXYCERTINFO_V3 "1.3.6.1.4.1.3536.1.222" +#define PROXYCERTINFO_V4 "1.3.6.1.5.5.7.1.14" + +/* error handling */ +#define ASN1_F_PROXYPOLICY_NEW 450 +#define ASN1_F_D2I_PROXYPOLICY 451 +#define ASN1_F_PROXYCERTINFO_NEW 430 +#define ASN1_F_D2I_PROXYCERTINFO 431 + +/* data structure */ + +typedef struct myPROXYPOLICY_st { + + ASN1_OBJECT * policy_language; + ASN1_OCTET_STRING * policy; + +} myPROXYPOLICY; + +typedef struct myPROXYCERTINFO_st { + + ASN1_INTEGER * path_length; + myPROXYPOLICY * proxypolicy; + int version; +} myPROXYCERTINFO; + + +/* myPROXYPOLICY function */ + +/* allocating and free memory */ +extern myPROXYPOLICY * myPROXYPOLICY_new(); +extern void myPROXYPOLICY_free(myPROXYPOLICY * proxypolicy); + +/* duplicate */ +extern myPROXYPOLICY * myPROXYPOLICY_dup(myPROXYPOLICY * policy); + +/* set policy language */ +extern int myPROXYPOLICY_set_policy_language(myPROXYPOLICY * policy, ASN1_OBJECT * policy_language); + +/* get policy language */ +extern ASN1_OBJECT * myPROXYPOLICY_get_policy_language(myPROXYPOLICY * policy); + +/* set policy contents */ +extern int myPROXYPOLICY_set_policy(myPROXYPOLICY * proxypolicy, unsigned char * policy, int length); + +/* get policy contents */ +extern unsigned char * myPROXYPOLICY_get_policy(myPROXYPOLICY * policy, int * length); + +/* internal to der conversion */ +extern int i2d_myPROXYPOLICY(myPROXYPOLICY * policy, unsigned char ** pp); + +/* der to internal conversion */ +extern myPROXYPOLICY * d2i_myPROXYPOLICY(myPROXYPOLICY ** policy, unsigned char ** pp, long length); + +/*myPROXYCERTINFO function */ + +/* allocating and free memory */ +extern myPROXYCERTINFO * myPROXYCERTINFO_new(); +extern void myPROXYCERTINFO_free(myPROXYCERTINFO * proxycertinfo); + +/* set path_length */ +extern int myPROXYCERTINFO_set_path_length(myPROXYCERTINFO * proxycertinfo, long path_length); + +/* get ptah length */ +extern long myPROXYCERTINFO_get_path_length(myPROXYCERTINFO * proxycertinfo); + +/* set proxypolicy */ +extern int myPROXYCERTINFO_set_proxypolicy(myPROXYCERTINFO * proxycertinfo, myPROXYPOLICY * proxypolicy); + +/* get proxypolicy */ +extern myPROXYPOLICY * myPROXYCERTINFO_get_proxypolicy(myPROXYCERTINFO * proxycertinfo); + +/* internal to der conversion */ +extern int i2d_myPROXYCERTINFO(myPROXYCERTINFO * proxycertinfo, unsigned char ** pp); + +/* der to internal conversion */ +extern myPROXYCERTINFO * d2i_myPROXYCERTINFO(myPROXYCERTINFO ** cert_info, unsigned char ** a, long length); + +extern int myPROXYCERTINFO_set_version(myPROXYCERTINFO *cert_info, int version); + +extern int proxynative(void); +extern void InitProxyCertInfoExtension(int full); + +#endif diff --git a/emi.canl.canl-c/src/proxy/namespaces.l b/emi.canl.canl-c/src/proxy/namespaces.l new file mode 100644 index 0000000..bfd8c84 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/namespaces.l @@ -0,0 +1,67 @@ +%{ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" +#include +#include + +#include + +#include "parsertypes.h" +#include "namespaces.h" +extern char *strndup(const char*, size_t); +%} + +%x SINGLE_QUOTED +%x DOUBLE_QUOTED + +%option reentrant +%option noyywrap +%option prefix="namespaces" +%option bison-bridge + +%% + +\#.* /* comment. Ignore */ + +\' BEGIN(SINGLE_QUOTED); + +[^']*\' yytext[strlen(yytext)-1]='\0'; yylval_param->string = yytext; BEGIN(INITIAL); return SUBJECT; + +\" BEGIN(DOUBLE_QUOTED); +[^"]*\" yytext[strlen(yytext)-1]='\0'; yylval_param->string = yytext; BEGIN(INITIAL); return SUBJECT; + + +(?i:TO) return TO; +(?i:ISSUER) return ISSUER; +(?i:PERMIT) return PERMIT; +(?i:DENY) return DENY; +(?i:SELF) return SELF; +(?i:SUBJECT) return SUBJECT_WORD; +\\$ +\n +. + +%% diff --git a/emi.canl.canl-c/src/proxy/namespaces.y b/emi.canl.canl-c/src/proxy/namespaces.y new file mode 100644 index 0000000..23e5193 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/namespaces.y @@ -0,0 +1,126 @@ +%{ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" +#include +#include +#include + +#include "parsertypes.h" +#include "listfunc.h" + +char **parse_subjects(char *string); +void namespaceserror(void *policies, void *scanner, char const *msg); +%} + +%error-verbose +%pure-parser +%name-prefix="namespaces" +%parse-param {struct policy ***policies} +%parse-param {void *scanner} +%lex-param {void *scanner} + +%union{ + char *string; + struct condition *cond; + struct policy *policy; + int integer; +} + +%token SUBJECT +%token TO +%token SELF +%token PERMIT +%token DENY +%token SUBJECT_WORD +%token ISSUER + +%type rule +%type condition +%type permit_or_deny + +%% + +eacl: rule { *policies = (struct policy**)listadd((char**)*policies, (char*)($1)); } +| eacl rule { *policies = (struct policy**)listadd((char**)*policies, (char*)($2)); } +; + +rule: TO ISSUER SUBJECT condition { + $$ = (struct policy *)calloc(1, sizeof(struct policy)); + if ($$) { + $$->self = 0; + $$->caname = strdup($3); + $$->conds = (struct condition**)listadd(NULL, (char*)($4)); + $$->type = TYPE_NAMESPACE; + } + + } +| TO ISSUER SELF condition { + $$ = (struct policy *)calloc(1, sizeof(struct policy)); + if ($$) { + $$->self = 1; + $$->caname = NULL; + $$->conds = (struct condition**)listadd(NULL, (char*)($4)); + $$->type = TYPE_NAMESPACE; + } + } +; + +condition: permit_or_deny SUBJECT_WORD SUBJECT { + $$ = (struct condition *)calloc(1, sizeof(struct condition)); + if ($$) { + $$->positive = $1; + $$->original = strdup($3); + $$->subjects = listadd(NULL, $$->original); + if (!$$->subjects) { + free($$->original); + free($$); + $$ = NULL; + } + } +} +; + +permit_or_deny: PERMIT { $$ = 1; } +| DENY { $$ = 0; } +; + +%% + +#if 0 +int main() +{ + namespacesdebug = 1; + struct policy **arg = NULL; + void *scanner=NULL; + namespaceslex_init(&scanner); + namespacesset_debug(1, scanner); + return namespacesparse(&arg, scanner); +} +#endif + +void namespaceserror(UNUSED(void *policies), UNUSED(void *scanner), UNUSED(char const *msg)) +{ +} diff --git a/emi.canl.canl-c/src/proxy/normalize.c b/emi.canl.canl-c/src/proxy/normalize.c new file mode 100644 index 0000000..ce445e5 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/normalize.c @@ -0,0 +1,89 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" + +#include +#include + +#include "doio.h" + +static char *change(const char *str, char *from, char *to) +{ + char *copy = strdup(str); + + if (!copy) + return NULL; + + char *pos = strstr(copy, from); + char *tmp = NULL; + + while (pos) { + *pos = '\0'; + tmp = snprintf_wrap("%s%s%s", copy, to, pos + strlen(from)); + if (tmp) { + free(copy); + copy = tmp; + } + pos = strstr(copy + strlen(to), from); + } + + return copy; +} + +char *normalize(const char *str) +{ + char *tmp = NULL; + char *tmp2 = NULL; + + tmp = change(str, "/USERID=", "/UID="); + tmp2 = change(tmp, "/emailAddress=", "/Email="); + free(tmp); + tmp = change(tmp2, "/E=", "/Email="); + free(tmp2); + return tmp; +} + +#if 0 +int main(int argc, char *argv) +{ + char *str1="/prova/Email=frge/CN=op"; + char *str2="/prova/E=boh/emailAddress=mah/E=op/CN=fr"; + char *str3="/USERID=56/mah"; + + char *n1 = normalize(str1); + char *n2 = normalize(str2); + char *n3 = normalize(str3); + + printf("%s -> %s\n", str1, n1); + free(n1); + printf("%s -> %s\n", str2, n2); + free(n2); + printf("%s -> %s\n", str3, n3); + free(n3); + + exit(0); +} + +#endif diff --git a/emi.canl.canl-c/src/proxy/normalize.h b/emi.canl.canl-c/src/proxy/normalize.h new file mode 100644 index 0000000..0ad0ab5 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/normalize.h @@ -0,0 +1,39 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ + +#ifndef _VOMS_NORMALIZE_H +#define _VOMS_NORMALIZE_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *normalize(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/emi.canl.canl-c/src/proxy/parsertypes.h b/emi.canl.canl-c/src/proxy/parsertypes.h new file mode 100644 index 0000000..84bdbf8 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/parsertypes.h @@ -0,0 +1,50 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * Valerio Venturi - Valerio.Venturi@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ + +#ifndef _OLDGAA_PARSERTYPES_H +#define _OLDGAA_PARSERTYPES_H + +struct condition { + char **subjects; + char *original; + int positive; +}; + +#define TYPE_SIGNING 0 +#define TYPE_NAMESPACE 1 + +struct policy { + char *caname; + int self; + int type; + struct condition **conds; +}; + +#define SUCCESS_PERMIT 0 +#define SUCCESS_DENY 1 +#define SUCCESS_UNDECIDED 2 + +#endif diff --git a/emi.canl.canl-c/src/proxy/proxy.c b/emi.canl.canl-c/src/proxy/proxy.c new file mode 100644 index 0000000..62378bb --- /dev/null +++ b/emi.canl.canl-c/src/proxy/proxy.c @@ -0,0 +1,884 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "vomsproxy.h" +#include "myproxycertinfo.h" +#include "sslutils.h" +#include "doio.h" + +static char *readfromfile(char *file, int *size, int *warning); +static void setWarning(int *warning, int value); +static void setAdditional(void **additional, void *data); +static X509_EXTENSION *set_KeyUsageFlags(int flags); +static int get_KeyUsageFlags(X509 *cert); +static X509_EXTENSION *set_ExtendedKeyUsageFlags(char *flagnames); +static char *getBitName(char**string); +static int getBitValue(char *bitname); +static int convertMethod(char *bits, int *warning, void **additional); +static X509_EXTENSION *get_BasicConstraints(int ca); + +struct VOMSProxyArguments *VOMS_MakeProxyArguments() +{ + return (struct VOMSProxyArguments*)calloc(1, sizeof(struct VOMSProxyArguments)); +} + +void VOMS_FreeProxyArguments(struct VOMSProxyArguments *args) +{ + free(args); +} + +void VOMS_FreeProxy(struct VOMSProxy *proxy) +{ + if (proxy) { + X509_free(proxy->cert); + sk_X509_pop_free(proxy->chain, X509_free); + EVP_PKEY_free(proxy->key); + free(proxy); + } +} + +struct VOMSProxy *VOMS_AllocProxy() +{ + return (struct VOMSProxy*)calloc(1, sizeof(struct VOMSProxy)); +} + +int VOMS_WriteProxy(const char *filename, struct VOMSProxy *proxy) +{ + int ret = -1; + int fd = -1; + int retry = 3; + BIO *bp = NULL; + + while (fd < 0 && retry > 0) { + unlink(filename); + fd = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + retry --; + } + +#ifndef WIN32 + if (fd != -1) { + if (fchmod(fd, S_IRUSR|S_IWUSR) < 0) { + close(fd); + return -1; + } + } +#endif + + if (fd != -1) { + if ((bp = BIO_new_fd(fd, BIO_NOCLOSE)) != NULL) { + ret = proxy_marshal_bp(bp, proxy->cert, proxy->key, NULL, proxy->chain); + BIO_free(bp); + } + close(fd); + } + + return ret; +} + + +static int kpcallback(int UNUSED(p), int UNUSED(n)) +{ + return 0; +} + +#define SET_EXT(ex) (!sk_X509_EXTENSION_push(extensions, (ex)) ? \ + (PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT), 0) : \ + ((ex = ((X509_EXTENSION*)NULL)), 1)) + +struct VOMSProxy *VOMS_MakeProxy(struct VOMSProxyArguments *args, int *warning, void **additional) +{ + char *value = NULL; + + X509 * ncert = NULL; + EVP_PKEY * npkey = NULL; + X509_REQ * req = NULL; + STACK_OF(X509_EXTENSION) * extensions = NULL; + int ku_flags = 0; + char *policy = NULL; + + X509_EXTENSION *ex1 = NULL, *ex2 = NULL, *ex3 = NULL, + *ex4 = NULL, *ex5 = NULL, *ex6 = NULL, *ex7 = NULL, + *ex8 = NULL, *ex9 = NULL, *ex10 = NULL, *ex11 = NULL, + *ex12 = NULL, *ex13 = NULL; + + int i = 0; + + struct VOMSProxy *proxy = NULL; + + static int init = 0; + + int (*cback)(); + + if (!init) { + InitProxyCertInfoExtension(1); + init = 1; + } + + setWarning(warning, PROXY_NO_ERROR); + + if (args->callback) + cback = args->callback; + else + cback = kpcallback; + + + if (args->proxyrequest == NULL) { + if (proxy_genreq(args->cert, &req, &npkey, args->bits, + args->newsubject ? args->newsubject : NULL, + (int (*)())cback)) + goto err; + } + else + req = args->proxyrequest; + + /* initialize extensions stack */ + + if ((extensions = sk_X509_EXTENSION_new_null()) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + /* Add passed extensions */ + if (args->extensions) { + int proxyindex; + + for (proxyindex = 0; proxyindex < sk_X509_EXTENSION_num(args->extensions); proxyindex++) { + X509_EXTENSION *ext = X509_EXTENSION_dup(sk_X509_EXTENSION_value(args->extensions, i)); + if (ext) { + if (!sk_X509_EXTENSION_push(extensions, ext)) { + X509_EXTENSION_free(ext); + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + } + else { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + } + } + /* Add proxy extensions */ + + /* voms extension */ + + if (args->datalen) { + if ((ex1 = CreateProxyExtension("voms", args->data, args->datalen, 0)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (!SET_EXT(ex1)) + goto err; + } + + /* include extension */ + + if (args->filename) { + + int filesize; + char *filedata = readfromfile(args->filename, &filesize, warning); + + if (filedata) { + if ((ex3 = CreateProxyExtension("incfile", filedata, filesize, 0)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + free(filedata); + goto err; + } + + free(filedata); + if (!SET_EXT(ex3)) + goto err; + } + else { + setAdditional(additional, args->filename); + goto err; + } + } + + /* AC extension */ + + if (args->aclist) { + + if ((ex5 = X509V3_EXT_conf_nid(NULL, NULL, OBJ_txt2nid("acseq"), (char *)args->aclist)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (!SET_EXT(ex5)) + goto err; + } + + /* keyUsage extension */ + + if (args->keyusage) { + ku_flags = convertMethod(args->keyusage, warning, additional); + if (ku_flags == -1) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + } + else if (args->selfsigned) { + ku_flags = X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_KEY_CERT_SIGN | + X509v3_KU_CRL_SIGN; + } + else { + ku_flags = get_KeyUsageFlags(args->cert); + ku_flags &= ~X509v3_KU_KEY_CERT_SIGN; + ku_flags &= ~X509v3_KU_NON_REPUDIATION; + } + + if ((ex8 = set_KeyUsageFlags(ku_flags)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + X509_EXTENSION_set_critical(ex8, 1); + + if (!SET_EXT(ex8)) + goto err; + + /* netscapeCert extension */ + if (args->netscape) { + + if ((ex9 = X509V3_EXT_conf_nid(NULL, NULL, NID_netscape_cert_type, args->netscape)) == NULL) { + /* PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); */ + goto err; + } + + if (!SET_EXT(ex9)) + goto err; + } + + /* extended key usage */ + + if (args->exkusage) { + if ((ex10 = set_ExtendedKeyUsageFlags(args->exkusage)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + setWarning(warning, PROXY_ERROR_UNKNOWN_EXTENDED_BIT); + setAdditional(additional,args->exkusage); + goto err; + } + + if (!SET_EXT(ex10)) + goto err; + } + + /* Basic Constraints */ + + if ((ex12 = get_BasicConstraints(args->selfsigned ? 1 : 0)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + X509_EXTENSION_set_critical(ex12, 1); + + if (!SET_EXT(ex12)) + goto err; + + /* vo extension */ + + if (strlen(args->voID)) { + if ((ex4 = CreateProxyExtension("vo", args->voID, strlen(args->voID), 0)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (!SET_EXT(ex4)) + goto err; + } + + /* authority key identifier and subject key identifier extension */ + + { + X509V3_CTX ctx; + + X509V3_set_ctx(&ctx, (args->selfsigned ? NULL : args->cert), NULL, req, NULL, 0); + + if (args->selfsigned) { + X509 *tmpcert = NULL; + ex13 = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, "hash"); + + if (!ex13) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (!SET_EXT(ex13)) + goto err; + + tmpcert = X509_new(); + if (tmpcert) { + EVP_PKEY *key = X509_REQ_get_pubkey(req); + X509_set_pubkey(tmpcert, key); + X509_add_ext(tmpcert, ex13, -1); + X509V3_set_ctx(&ctx, tmpcert, tmpcert, req, NULL, 0); + ex11 = X509V3_EXT_conf_nid(NULL, &ctx, NID_authority_key_identifier, "keyid"); + X509_free(tmpcert); + EVP_PKEY_free(key); + } + else + ex11 = NULL; + } + else { + ex11 = X509V3_EXT_conf_nid(NULL, &ctx, NID_authority_key_identifier, "keyid"); + } + + if (!ex11) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (!SET_EXT(ex11)) + goto err; + } + + /* class_add extension */ + +#ifdef CLASS_ADD + + if (class_add_buf && class_add_buf_len > 0) { + if ((ex2 = proxy_extension_class_add_create((void *)args->class_add_buf, args->class_add_buf_len)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (!SET_EXT(ex2)) + goto err; + } + +#endif + + /* PCI extension */ + + if (args->proxyversion>=3) { + myPROXYPOLICY * proxypolicy; + myPROXYCERTINFO * proxycertinfo = NULL; + ASN1_OBJECT * policy_language; + + /* getting contents of policy file */ + + int policysize = 0; + char *policylang = args->policylang; + + if (args->policyfile) { + policy = readfromfile(args->policyfile, &policysize, warning); + + if (!policy) { + setAdditional(additional, args->policyfile); + goto err; + } + } + + /* setting policy language field */ + + if (!policylang) { + if (!args->policyfile) { + policylang = IMPERSONATION_PROXY_OID; + setWarning(warning, PROXY_WARNING_GSI_ASSUMED); + } + else { + policylang = GLOBUS_GSI_PROXY_GENERIC_POLICY_OID; + setWarning(warning, PROXY_WARNING_GENERIC_LANGUAGE_ASSUMED); + } + } + + /* predefined policy language can be specified with simple name string */ + + else if (strcmp(policylang, IMPERSONATION_PROXY_SN) == 0) + policylang = IMPERSONATION_PROXY_OID; + else if (strcmp(policylang, INDEPENDENT_PROXY_SN) == 0) + policylang = INDEPENDENT_PROXY_OID; + + /* does limited prevail on others? don't know what does grid-proxy_init since if pl is given with + limited options it crash */ + if (args->limited) + policylang = LIMITED_PROXY_OID; + + OBJ_create(policylang, policylang, policylang); + + if (!(policy_language = OBJ_nid2obj(OBJ_sn2nid(policylang)))) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_OID); + goto err; + } + + int nativeopenssl = proxynative(); + + if (args->proxyversion == 3 || (args->proxyversion == 4 && !nativeopenssl)) { + /* proxypolicy */ + + proxypolicy = myPROXYPOLICY_new(); + + if (policy) { + myPROXYPOLICY_set_policy(proxypolicy, (unsigned char*)policy, policysize); + free(policy); + policy = NULL; + } + else if (args->policytext) + myPROXYPOLICY_set_policy(proxypolicy, + (unsigned char*)args->policytext, + strlen(args->policytext)); + + myPROXYPOLICY_set_policy_language(proxypolicy, policy_language); + + /* proxycertinfo */ + + proxycertinfo = myPROXYCERTINFO_new(); + myPROXYCERTINFO_set_version(proxycertinfo, args->proxyversion); + myPROXYCERTINFO_set_proxypolicy(proxycertinfo, proxypolicy); + + myPROXYPOLICY_free(proxypolicy); + + if (args->pathlength>=0) + myPROXYCERTINFO_set_path_length(proxycertinfo, args->pathlength); + + value = (char *)proxycertinfo; + } + else { + if (args->pathlength != -1) { + char *buffer = snprintf_wrap("%d", args->pathlength); + + if (policy) { + value = snprintf_wrap("language:%s,pathlen:%s,policy:text:%s", policylang, buffer, policy); + free(policy); + policy = NULL; + } + else if (args->policytext) + value = snprintf_wrap("language:%s,pathlen:%s,policy:text:%s", policylang, buffer, args->policytext); + else + value = snprintf_wrap("language:%s,pathlen:%s", policylang, buffer); + free(buffer); + } + else { + if (policy) + value = snprintf_wrap("language:%s,policy:text:%s", policylang, policy); + else if (args->policytext) + value = snprintf_wrap("language:%s,policy:text:%s", policylang, args->policytext); + else + value = snprintf_wrap("language:%s", policylang); + } + } + + if (args->proxyversion == 3) { + ex7 = X509V3_EXT_conf_nid(NULL, NULL, my_txt2nid(PROXYCERTINFO_V3), (char*)proxycertinfo); + value = NULL; + } else { + if (nativeopenssl) { + X509V3_CTX ctx; + X509V3_set_ctx(&ctx, NULL, NULL, NULL, NULL, 0L); + ctx.db = (void*)&ctx; + X509V3_CONF_METHOD method = { NULL, NULL, NULL, NULL }; + ctx.db_meth = &method; + ex7 = X509V3_EXT_conf_nid(NULL, &ctx, my_txt2nid(PROXYCERTINFO_V4), (char*)value); + free(value); + value = NULL; + } + else + ex7 = X509V3_EXT_conf_nid(NULL, NULL, my_txt2nid(PROXYCERTINFO_V4), (char*)value); + value = NULL; + } + + if (policy) { + free(policy); + policy = NULL; + } + + if (ex7 == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN, PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + if (args->proxyversion == 4) { + X509_EXTENSION_set_critical(ex7, 1); + } + + if (!SET_EXT(ex7)) + goto err; + } + + if (!args->selfsigned) { + if (proxy_sign(args->cert, + args->key, + req, + &ncert, + args->hours*60*60 + args->minutes*60, + extensions, + args->limited, + args->proxyversion, + args->newsubject, + args->newissuer, + args->pastproxy, + args->newserial, + args->selfsigned)) { + goto err; + } + } + else { + if (proxy_sign(NULL, + npkey, + req, + &ncert, + args->hours*60*60 + args->minutes*60, + extensions, + args->limited, + 0, + args->newsubject, + args->newsubject, + args->pastproxy, + NULL, + args->selfsigned)) { + goto err; + } + } + + proxy = (struct VOMSProxy*)malloc(sizeof(struct VOMSProxy)); + + if (proxy) { + proxy->cert = ncert; + proxy->key = npkey; + proxy->chain = sk_X509_new_null(); + + if (args->cert) + sk_X509_push(proxy->chain, X509_dup(args->cert)); + + for (i = 0; i < sk_X509_num(args->chain); i++) + sk_X509_push(proxy->chain, X509_dup(sk_X509_value(args->chain, i))); + } + + err: + + if (!proxy) { + X509_free(ncert); + EVP_PKEY_free(npkey); + } + + if (extensions) { + sk_X509_EXTENSION_pop_free(extensions, X509_EXTENSION_free); + } + if (!args->proxyrequest) + X509_REQ_free(req); + + X509_EXTENSION_free(ex13); + X509_EXTENSION_free(ex12); + X509_EXTENSION_free(ex11); + X509_EXTENSION_free(ex10); + X509_EXTENSION_free(ex9); + X509_EXTENSION_free(ex8); + X509_EXTENSION_free(ex6); + X509_EXTENSION_free(ex7); + X509_EXTENSION_free(ex5); + X509_EXTENSION_free(ex2); + X509_EXTENSION_free(ex3); + X509_EXTENSION_free(ex4); + X509_EXTENSION_free(ex1); + free(policy); + free(value); + return proxy; +} + +X509_EXTENSION *CreateProxyExtension(char * name, char *data, int datalen, int crit) +{ + + X509_EXTENSION * ex = NULL; + ASN1_OBJECT * ex_obj = NULL; + ASN1_OCTET_STRING * ex_oct = NULL; + + int nid = OBJ_txt2nid(name); + + if (nid != 0) + ex_obj = OBJ_nid2obj(nid); + else + ex_obj = OBJ_txt2obj(name, 0); + + if (!ex_obj) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_OID); + goto err; + } + + if (!(ex_oct = ASN1_OCTET_STRING_new())) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + ex_oct->data = (unsigned char*)data; + ex_oct->length = datalen; + + if (!(ex = X509_EXTENSION_create_by_OBJ(NULL, ex_obj, crit, ex_oct))) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + } + + err: + + if (ex_oct) { + /* avoid spurious free of the contents. */ + ex_oct->length = 0; + ex_oct->data = NULL; + ASN1_OCTET_STRING_free(ex_oct); + } + + ASN1_OBJECT_free(ex_obj); + + return ex; + +} + + +static char *readfromfile(char *file, int *size, int *warning) +{ + int fd = open(file,O_RDONLY); + char *buffer = NULL; + + if (fd != -1) { + struct stat filestats; + + if (!fstat(fd, &filestats)) { + *size = filestats.st_size; + + buffer = (char *)malloc(*size); + + if (buffer) { + int offset = 0; + int ret = 0; + + do { + ret = read(fd, buffer+offset, *size - offset); + offset += ret; + } while ( ret > 0); + + if (ret < 0) { + free(buffer); + buffer = NULL; + setWarning(warning, PROXY_ERROR_FILE_READ); + } + } + else + setWarning(warning, PROXY_ERROR_OUT_OF_MEMORY); + } + else + setWarning(warning, PROXY_ERROR_STAT_FILE); + close(fd); + } + else + setWarning(warning, PROXY_ERROR_OPEN_FILE); + + + return buffer; +} + +static void setWarning(int *warning, int value) +{ + if (warning) + *warning = value; +} + +static void setAdditional(void **additional, void *data) +{ + if (additional) + *additional = data; +} + +static X509_EXTENSION *set_KeyUsageFlags(int flags) +{ + unsigned char data[2]; + + X509_EXTENSION *ext = NULL; + ASN1_BIT_STRING *str = ASN1_BIT_STRING_new(); + + if (str) { + int len =0; + + data[0] = flags & 0x00ff; + data[1] = (flags & 0xff00) >> 8; + + len = (data[1] ? 2 : 1); + + ASN1_BIT_STRING_set(str, data, len); + + ext = X509V3_EXT_i2d(NID_key_usage, 1, str); + ASN1_BIT_STRING_free(str); + + return ext; + } + + return NULL; +} + +static X509_EXTENSION *set_ExtendedKeyUsageFlags(char *flagnames) +{ + if (!flagnames) + return NULL; + + return X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage, flagnames); +} + +static X509_EXTENSION *get_BasicConstraints(int ca) +{ + return X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, (ca ? "CA:true" : "CA:false")); +} + +static int get_KeyUsageFlags(X509 *cert) +{ + int keyusage = 0; + + ASN1_BIT_STRING *usage = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL); + + if (usage) { + if (usage->length > 0) + keyusage = usage->data[0]; + if (usage->length > 1) + keyusage |= usage->data[1] << 8; + + ASN1_BIT_STRING_free(usage); + } + + return keyusage; +} + +static char *getBitName(char**string) +{ + char *div = NULL; + char *temp = NULL; + + if (!string || !(*string) || (*(*string) == '\0')) + return NULL; + + div = strchr(*string, ','); + + if (div) { + temp = *string; + *div++ = '\0'; + *string = div; + } + else { + temp = *string; + *string = *string + strlen(*string); + } + + return temp; +} + +static int getBitValue(char *bitname) +{ + if (!strcmp(bitname, "digitalSignature")) + return KU_DIGITAL_SIGNATURE; + else if (!strcmp(bitname, "nonRepudiation")) + return KU_NON_REPUDIATION; + else if (!strcmp(bitname, "keyEncipherment")) + return KU_KEY_ENCIPHERMENT; + else if (!strcmp(bitname, "dataEncipherment")) + return KU_DATA_ENCIPHERMENT; + else if (!strcmp(bitname, "keyAgreement")) + return KU_KEY_AGREEMENT; + else if (!strcmp(bitname, "keyCertSign")) + return KU_KEY_CERT_SIGN; + else if (!strcmp(bitname, "cRLSign")) + return KU_CRL_SIGN; + else if (!strcmp(bitname, "encipherOnly")) + return KU_ENCIPHER_ONLY; + else if (!strcmp(bitname, "decipherOnly")) + return KU_DECIPHER_ONLY; + + return 0; +} + + +static int convertMethod(char *bits, int *warning, void **additional) +{ + char *bitname = NULL; + int value = 0; + int total = 0; + + while ((bitname = getBitName(&bits))) { + value = getBitValue(bitname); + if (value == 0) { + setWarning(warning, PROXY_ERROR_UNKNOWN_BIT); + setAdditional(additional, bitname); + return -1; + } + total |= value; + } + + return total; +} + +char *ProxyCreationError(int error, void *additional) +{ + switch (error) { + case PROXY_NO_ERROR: + return NULL; + break; + + case PROXY_ERROR_OPEN_FILE: + return snprintf_wrap("Error: cannot open file: %s\n%s\n", additional, strerror(errno)); + break; + + case PROXY_ERROR_FILE_READ: + return snprintf_wrap("Error: cannot read from file: %s\n%s\n", additional, strerror(errno)); + break; + + case PROXY_ERROR_STAT_FILE: + return snprintf_wrap("Error: cannot stat file: %s\n%s\n", additional, strerror(errno)); + break; + + case PROXY_ERROR_OUT_OF_MEMORY: + return snprintf_wrap("Error: out of memory"); + break; + + case PROXY_ERROR_UNKNOWN_BIT: + return snprintf_wrap("KeyUsage bit: %s unknown\n", additional); + break; + + case PROXY_ERROR_UNKNOWN_EXTENDED_BIT: + return snprintf_wrap("ExtKeyUsage bit value: %s invalid. One or more of the bits are unknown\n", additional); + break; + + case PROXY_WARNING_GSI_ASSUMED: + return snprintf_wrap("\nNo policy language specified, Gsi impersonation proxy assumed."); + break; + + case PROXY_WARNING_GENERIC_LANGUAGE_ASSUMED: + return snprintf_wrap("\nNo policy language specified with policy file, assuming generic."); + break; + + default: + return snprintf_wrap("Unknown error"); + break; + } +} diff --git a/emi.canl.canl-c/src/proxy/proxycertinfo.c b/emi.canl.canl-c/src/proxy/proxycertinfo.c new file mode 100644 index 0000000..a944ea1 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/proxycertinfo.c @@ -0,0 +1,511 @@ +/********************************************************************* + * + * Authors: Valerio Venturi - Valerio.Venturi@cnaf.infn.it + * Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" + +#include + +#include +#include +#include + +#include "myproxycertinfo.h" +#include "doio.h" + +/* myPROXYPOLICY function */ + +myPROXYPOLICY * myPROXYPOLICY_new() +{ + ASN1_CTX c; + myPROXYPOLICY * ret; + + ret = NULL; + + M_ASN1_New_Malloc(ret, myPROXYPOLICY); + ret->policy_language = OBJ_nid2obj(OBJ_sn2nid(IMPERSONATION_PROXY_SN)); + ret->policy = NULL; + return (ret); + M_ASN1_New_Error(ASN1_F_PROXYPOLICY_NEW); +} + +void myPROXYPOLICY_free(myPROXYPOLICY * policy) +{ + if(policy == NULL) return; + + ASN1_OBJECT_free(policy->policy_language); + M_ASN1_OCTET_STRING_free(policy->policy); + OPENSSL_free(policy); +} + +/* duplicate */ +myPROXYPOLICY * myPROXYPOLICY_dup(myPROXYPOLICY * policy) +{ +#ifdef TYPEDEF_I2D_OF + return ((myPROXYPOLICY *) ASN1_dup((i2d_of_void *)i2d_myPROXYPOLICY, + (d2i_of_void *)d2i_myPROXYPOLICY, + (char *)policy)); +#else + return ((myPROXYPOLICY *) ASN1_dup((int (*)())i2d_myPROXYPOLICY, + (char *(*)())d2i_myPROXYPOLICY, + (char *)policy)); +#endif +} + +/* set policy language */ +int myPROXYPOLICY_set_policy_language(myPROXYPOLICY * policy, ASN1_OBJECT * policy_language) +{ + if(policy_language != NULL) { + ASN1_OBJECT_free(policy->policy_language); + policy->policy_language = OBJ_dup(policy_language); + return 1; + } + + return 0; +} + +/* get policy language */ +ASN1_OBJECT * myPROXYPOLICY_get_policy_language(myPROXYPOLICY * policy) +{ + return policy->policy_language; +} + +/* set policy */ +int myPROXYPOLICY_set_policy(myPROXYPOLICY * proxypolicy, unsigned char * policy, int length) +{ + if(policy != NULL) { + /* if member policy of proxypolicy non set */ + if(!proxypolicy->policy) + proxypolicy->policy = ASN1_OCTET_STRING_new(); + + /* set member policy of proxypolicy */ + ASN1_OCTET_STRING_set(proxypolicy->policy, policy, length); + } + else + ASN1_OCTET_STRING_free(proxypolicy->policy); + + return 1; +} + +/* get policy */ +unsigned char * myPROXYPOLICY_get_policy(myPROXYPOLICY * proxypolicy, int * length) +{ + /* assure field policy is set */ + + if(proxypolicy->policy) { + *length = proxypolicy->policy->length; + + /* assure ASN1_OCTET_STRING is full */ + if (*length>0 && proxypolicy->policy->data) { + unsigned char * copy = malloc(*length); + memcpy(copy, proxypolicy->policy->data, *length); + return copy; + } + } + return NULL; +} + +/* internal to der conversion */ +int i2d_myPROXYPOLICY(myPROXYPOLICY * policy, unsigned char ** pp) +{ + M_ASN1_I2D_vars(policy); + + M_ASN1_I2D_len(policy->policy_language, i2d_ASN1_OBJECT); + + if(policy->policy) { + M_ASN1_I2D_len(policy->policy, i2d_ASN1_OCTET_STRING); + } + + M_ASN1_I2D_seq_total(); + M_ASN1_I2D_put(policy->policy_language, i2d_ASN1_OBJECT); + + if(policy->policy) { + M_ASN1_I2D_put(policy->policy, i2d_ASN1_OCTET_STRING); + } + + M_ASN1_I2D_finish(); +} + +myPROXYPOLICY * d2i_myPROXYPOLICY(myPROXYPOLICY ** a, unsigned char ** pp, long length) +{ + M_ASN1_D2I_vars(a, myPROXYPOLICY *, myPROXYPOLICY_new); + + M_ASN1_D2I_Init(); + M_ASN1_D2I_start_sequence(); + M_ASN1_D2I_get(ret->policy_language, d2i_ASN1_OBJECT); + + /* need to try getting the policy using + * a) a call expecting no tags + * b) a call expecting tags + * one of which should succeed + */ + + M_ASN1_D2I_get_opt(ret->policy, + d2i_ASN1_OCTET_STRING, + V_ASN1_OCTET_STRING); + M_ASN1_D2I_get_IMP_opt(ret->policy, + d2i_ASN1_OCTET_STRING, + 0, + V_ASN1_OCTET_STRING); + M_ASN1_D2I_Finish(a, + myPROXYPOLICY_free, + ASN1_F_D2I_PROXYPOLICY); +} + + + +/* myPROXYCERTINFO function */ + +myPROXYCERTINFO * myPROXYCERTINFO_new() +{ + myPROXYCERTINFO * ret = NULL; + ASN1_CTX c; + + M_ASN1_New_Malloc(ret, myPROXYCERTINFO); + memset(ret, 0, sizeof(myPROXYCERTINFO)); + ret->path_length = NULL; + ret->proxypolicy = myPROXYPOLICY_new(); + return (ret); + M_ASN1_New_Error(ASN1_F_PROXYCERTINFO_NEW); +} + +void myPROXYCERTINFO_free(myPROXYCERTINFO * proxycertinfo) +{ + /* assure proxycertinfo not empty */ + if(proxycertinfo == NULL) return; + + ASN1_INTEGER_free(proxycertinfo->path_length); + myPROXYPOLICY_free(proxycertinfo->proxypolicy); + OPENSSL_free(proxycertinfo); +} + +/* set path_length */ +int myPROXYCERTINFO_set_path_length(myPROXYCERTINFO * proxycertinfo, long path_length) +{ + /* assure proxycertinfo is not empty */ + if(proxycertinfo != NULL) { + + if(path_length != -1) { + /* if member path_length is empty allocate memory then set */ + if(proxycertinfo->path_length == NULL) + proxycertinfo->path_length = ASN1_INTEGER_new(); + return ASN1_INTEGER_set(proxycertinfo->path_length, path_length); + } + else { + ASN1_INTEGER_free(proxycertinfo->path_length); + proxycertinfo->path_length = NULL; + } + + return 1; + } + + return 0; +} + +int myPROXYCERTINFO_set_version(myPROXYCERTINFO * proxycertinfo, int version) +{ + if (proxycertinfo != NULL) { + proxycertinfo->version = version; + return 1; + } + + return 0; +} + +int myPROXYCERTINFO_get_version(myPROXYCERTINFO * proxycertinfo) +{ + if (proxycertinfo) + return proxycertinfo->version; + return -1; +} + + +/* get path length */ +long myPROXYCERTINFO_get_path_length(myPROXYCERTINFO * proxycertinfo) +{ + if(proxycertinfo && proxycertinfo->path_length) + return ASN1_INTEGER_get(proxycertinfo->path_length); + else + return -1; +} + +/* set policy */ +int myPROXYCERTINFO_set_proxypolicy(myPROXYCERTINFO * proxycertinfo, myPROXYPOLICY * proxypolicy) +{ + myPROXYPOLICY_free(proxycertinfo->proxypolicy); + + if(proxypolicy != NULL) + proxycertinfo->proxypolicy = myPROXYPOLICY_dup(proxypolicy); + else + proxycertinfo->proxypolicy = NULL; + + return 1; +} + +/* get policy */ +myPROXYPOLICY * myPROXYCERTINFO_get_proxypolicy(myPROXYCERTINFO * proxycertinfo) +{ + if(proxycertinfo) + return proxycertinfo->proxypolicy; + + return NULL; +} + +/* internal to der conversion */ +static int i2d_myPROXYCERTINFO_v3(myPROXYCERTINFO * proxycertinfo, unsigned char ** pp) +{ + int v1; + + M_ASN1_I2D_vars(proxycertinfo); + + v1 = 0; + + M_ASN1_I2D_len(proxycertinfo->proxypolicy, i2d_myPROXYPOLICY); + + M_ASN1_I2D_len_EXP_opt(proxycertinfo->path_length,i2d_ASN1_INTEGER, 1, v1); + M_ASN1_I2D_seq_total(); + M_ASN1_I2D_put(proxycertinfo->proxypolicy, i2d_myPROXYPOLICY); + M_ASN1_I2D_put_EXP_opt(proxycertinfo->path_length, i2d_ASN1_INTEGER, 1, v1); + M_ASN1_I2D_finish(); +} + +static int i2d_myPROXYCERTINFO_v4(myPROXYCERTINFO * proxycertinfo, unsigned char ** pp) +{ + M_ASN1_I2D_vars(proxycertinfo); + + if(proxycertinfo->path_length) + { + M_ASN1_I2D_len(proxycertinfo->path_length, i2d_ASN1_INTEGER); + } + + M_ASN1_I2D_len(proxycertinfo->proxypolicy, i2d_myPROXYPOLICY); + + M_ASN1_I2D_seq_total(); + if(proxycertinfo->path_length) + { + M_ASN1_I2D_put(proxycertinfo->path_length, i2d_ASN1_INTEGER); + } + M_ASN1_I2D_put(proxycertinfo->proxypolicy, i2d_myPROXYPOLICY); + M_ASN1_I2D_finish(); +} + +int i2d_myPROXYCERTINFO(myPROXYCERTINFO * proxycertinfo, unsigned char ** pp) +{ + switch(proxycertinfo->version) { + case 3: + return i2d_myPROXYCERTINFO_v3(proxycertinfo, pp); + break; + + case 4: + return i2d_myPROXYCERTINFO_v4(proxycertinfo, pp); + break; + + default: + return -1; + break; + } +} + +static myPROXYCERTINFO * d2i_myPROXYCERTINFO_v3(myPROXYCERTINFO ** cert_info, unsigned char ** pp, long length) +{ + M_ASN1_D2I_vars(cert_info, myPROXYCERTINFO *, myPROXYCERTINFO_new); + + M_ASN1_D2I_Init(); + M_ASN1_D2I_start_sequence(); + + M_ASN1_D2I_get((ret->proxypolicy), d2i_myPROXYPOLICY); + + M_ASN1_D2I_get_EXP_opt(ret->path_length, d2i_ASN1_INTEGER, 1); + + ret->version = 3; + M_ASN1_D2I_Finish(cert_info, myPROXYCERTINFO_free, ASN1_F_D2I_PROXYCERTINFO); +} + +static myPROXYCERTINFO * d2i_myPROXYCERTINFO_v4(myPROXYCERTINFO ** cert_info, unsigned char ** pp, long length) +{ + M_ASN1_D2I_vars(cert_info, myPROXYCERTINFO *, myPROXYCERTINFO_new); + + M_ASN1_D2I_Init(); + M_ASN1_D2I_start_sequence(); + + M_ASN1_D2I_get_EXP_opt(ret->path_length, d2i_ASN1_INTEGER, 1); + + M_ASN1_D2I_get_opt(ret->path_length, d2i_ASN1_INTEGER, V_ASN1_INTEGER); + + M_ASN1_D2I_get((ret->proxypolicy),d2i_myPROXYPOLICY); + + ret->version = 4; + M_ASN1_D2I_Finish(cert_info, myPROXYCERTINFO_free, ASN1_F_D2I_PROXYCERTINFO); +} + +myPROXYCERTINFO * d2i_myPROXYCERTINFO(myPROXYCERTINFO ** cert_info, unsigned char ** pp, long length) +{ + myPROXYCERTINFO *info = d2i_myPROXYCERTINFO_v3(cert_info, pp, length); + if (!info) + info = d2i_myPROXYCERTINFO_v4(cert_info, pp, length); + return info; +} + + +static int nativeopenssl = 0; + +static char *norep() +{ + static char *buffer=""; + return buffer; +} + +static void *myproxycertinfo_s2i(UNUSED(struct v3_ext_method *method), UNUSED(struct v3_ext_ctx *ctx), UNUSED(char *data)) +{ + return (myPROXYCERTINFO*)data; +} + +static char *myproxycertinfo_i2s(UNUSED(struct v3_ext_method *method), void *ext) +{ + myPROXYCERTINFO *pci = NULL; + char *encoding = NULL; + char *output = NULL; + myPROXYPOLICY *pp; + int dooid = 0; + char oid[256]; + + pci = (myPROXYCERTINFO *)ext; + + if (!pci) + return norep(); + + if (pci->path_length) { + int j = ASN1_INTEGER_get(pci->path_length); + + char *buffer = snprintf_wrap("%X", j); + output = snprintf_wrap("Path Length Constraint: %s%s\n\n", strlen(buffer)%2 ? "0" : "", buffer); + free(buffer); + } + else + output = strdup("Path Length Constraint: unlimited\n"); + + pp = pci->proxypolicy; + + if (pp && i2t_ASN1_OBJECT(oid, 256, pp->policy_language)) { + dooid = 1; + } + + encoding = snprintf_wrap("%sPolicy Language: %s%s%s%s\n", + output, + ( dooid ? oid : ""), + ( (pp && pp->policy) ? "\nPolicy Text: " : ""), + ( (pp && pp->policy) ? (char*)ASN1_STRING_data(pp->policy) : ""), + ( (pp && pp->policy) ? "\n" : "")); + + free(output); + return encoding; +} + +void InitProxyCertInfoExtension(int full) +{ +#define PROXYCERTINFO_V3 "1.3.6.1.4.1.3536.1.222" +#define PROXYCERTINFO_V4 "1.3.6.1.5.5.7.1.14" +#define OBJC(c,n) OBJ_create(c,n,n) + + X509V3_EXT_METHOD *pcert; + static int set = 0; + ASN1_OBJECT *objv3; + ASN1_OBJECT *objv4; + + if (set) + return; + + set = 1; + + + objv3 = OBJ_txt2obj(PROXYCERTINFO_V3,1); + objv4 = OBJ_txt2obj(PROXYCERTINFO_V4,1); + + /* Proxy Certificate Extension's related objects */ + if (OBJ_obj2nid(objv3) == 0) { + ERR_clear_error(); + OBJC(PROXYCERTINFO_V3, "Proxy Certificate Information"); + if (full) { + pcert = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)); + + if (pcert) { + memset(pcert, 0, sizeof(*pcert)); + pcert->ext_nid = OBJ_txt2nid(PROXYCERTINFO_V3); + pcert->ext_flags = 0; + pcert->ext_new = (X509V3_EXT_NEW) myPROXYCERTINFO_new; + pcert->ext_free = (X509V3_EXT_FREE)myPROXYCERTINFO_free; + pcert->d2i = (X509V3_EXT_D2I) d2i_myPROXYCERTINFO; + pcert->i2d = (X509V3_EXT_I2D) i2d_myPROXYCERTINFO; + pcert->i2s = (X509V3_EXT_I2S) myproxycertinfo_i2s; + pcert->s2i = (X509V3_EXT_S2I) myproxycertinfo_s2i; + pcert->v2i = (X509V3_EXT_V2I) NULL; + pcert->r2i = (X509V3_EXT_R2I) NULL; + pcert->i2v = (X509V3_EXT_I2V) NULL; + pcert->i2r = (X509V3_EXT_I2R) NULL; + + X509V3_EXT_add(pcert); + } + } + } + + if (OBJ_obj2nid(objv4) == 0) { + ERR_clear_error(); + OBJC(PROXYCERTINFO_V4, "Proxy Certificate Information"); + if (full) { + pcert = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)); + + if (pcert) { + memset(pcert, 0, sizeof(*pcert)); + pcert->ext_nid = OBJ_txt2nid(PROXYCERTINFO_V4); + pcert->ext_flags = 0; + pcert->ext_new = (X509V3_EXT_NEW) myPROXYCERTINFO_new; + pcert->ext_free = (X509V3_EXT_FREE)myPROXYCERTINFO_free; + pcert->d2i = (X509V3_EXT_D2I) d2i_myPROXYCERTINFO; + pcert->i2d = (X509V3_EXT_I2D) i2d_myPROXYCERTINFO; + pcert->i2s = (X509V3_EXT_I2S) myproxycertinfo_i2s; + pcert->s2i = (X509V3_EXT_S2I) myproxycertinfo_s2i; + pcert->v2i = (X509V3_EXT_V2I) NULL; + pcert->r2i = (X509V3_EXT_R2I) NULL; + pcert->i2v = (X509V3_EXT_I2V) NULL; + pcert->i2r = (X509V3_EXT_I2R) NULL; + + X509V3_EXT_add(pcert); + } + } + } + +#ifdef X509_V_FLAG_ALLOW_PROXY_CERTS + nativeopenssl = 1; +#endif + + ASN1_OBJECT_free(objv3); + ASN1_OBJECT_free(objv4); + + return; +} + +int proxynative(void) +{ + return nativeopenssl; +} diff --git a/emi.canl.canl-c/src/proxy/scutils.c b/emi.canl.canl-c/src/proxy/scutils.c new file mode 100644 index 0000000..2bbad60 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/scutils.c @@ -0,0 +1,987 @@ +/********************************************************************** + +scutils.c + +Description: + Routines used internally to work with smart card + using PKCS11 + +**********************************************************************/ + +/********************************************************************** + Include header files +**********************************************************************/ +//#include "config.h" + +#ifdef USE_PKCS11 + +#include "scutils.h" +#include "sslutils.h" + +#ifndef WIN32 +#define FILE_SEPERATOR "/" +#else +#define FILE_SEPERATOR "\\" +#include +#endif + +#include +#include +#include + +#ifdef USE_PKCS11_DL +#include +#endif +#include "buffer.h" +#include "crypto.h" +#include "objects.h" +#include "asn1.h" +#include "evp.h" +#include "x509.h" +#include "pem.h" +#include "ssl.h" +#include "rsa.h" + + +/********************************************************************** + Type definitions +**********************************************************************/ + +/********************************************************************** + Module specific prototypes +**********************************************************************/ + +static int +sc_RSA_eay_private_decrypt(int flen, + unsigned char * from, + unsigned char * to, + RSA * rsa, + int padding); + +static int +sc_RSA_eay_private_encrypt(int flen, + unsigned char * from, + unsigned char * to, + RSA * rsa, + int padding); + +/********************************************************************** + Define module specific variables +**********************************************************************/ + +static ERR_STRING_DATA scerr_str_functs[]= +{ + {ERR_PACK(0,SCERR_F_RSA_ENCRYPT,0),"sc_RSA_private_encrypt"}, + {ERR_PACK(0,SCERR_F_RSA_DECRYPT,0),"sc_RSA_private_decrypt"}, + {ERR_PACK(0,SCERR_F_SCINIT,0),"sc_init"}, + {ERR_PACK(0,SCERR_F_GET_RSA_PRIV_KEY_OBJ,0),"sc_get_rsa_priv_key_obj"}, + {ERR_PACK(0,SCERR_F_GET_PRIV_KEY_OBJ,0),"sc_get_priv_key_obj"}, + {ERR_PACK(0,SCERR_F_GET_PRIV_KEY_BY_LABEL,0),"sc_get_priv_key_by_label"}, + {ERR_PACK(0,SCERR_F_GET_CERT_OBJ,0),"sc_get_cert_obj"}, + {ERR_PACK(0,SCERR_F_FIND_ONE_OBJ,0),"sc_find_one_obj"}, + {ERR_PACK(0,SCERR_F_FIND_CERT_BY_LABEL,0),"sc_find_cert_by_label"}, + {ERR_PACK(0,SCERR_F_LOAD_DLL,0),"sc_get_function_list"}, + {0,NULL}, +}; + +static ERR_STRING_DATA scerr_str_reasons[]= +{ + {SCERR_R_PKCS11_ERROR, "PKCS11 error"}, + {SCERR_R_SIGNINIT, "C_SignInit"}, + {SCERR_R_SIGN, "C_Sign"}, + {SCERR_R_SIGNRECINIT, "C_SignRecoverInit"}, + {SCERR_R_SIGNREC, "C_SignRecover"}, + {SCERR_R_INITIALIZE, "C_Initialize"}, + {SCERR_R_GETSLOTLIST, "C-GetSlotList"}, + {SCERR_R_OPENSESSION, "C_OpenSession"}, + {SCERR_R_LOGIN, "C_Login"}, + {SCERR_R_CREATEOBJ, "C_CreateObject"}, + {SCERR_R_UNSUPPORTED, "Unsupported feature"}, + {SCERR_R_GETATTRVAL, "C_GetAttributeValue"}, + {SCERR_R_FINDOBJINIT, "C_FindObjectInit"}, + {SCERR_R_FINDOBJ, "C_FindObject"}, + {SCERR_R_FOUNDMANY, "Found more then one matching key"}, + {SCERR_R_FIND_FAILED, "Unable to find object on smart card"}, + {SCERR_R_NO_PKCS11_DLL,"Unable to load the PKCS11 support"}, + {0,NULL}, +}; + +CK_FUNCTION_LIST_PTR pFunctionList = NULL; + +#ifdef WIN32 +HMODULE h_m_pkcs11 = NULL; +#else +void * h_m_pkcs11 = NULL; +#endif + +/********************************************************************** +Function: sc_get_function_list() + +Description: + Get the name of the PKCS11 dll to use from the registry, + load it, get the entry for the C_GetFunctionList + call it to set the pFunctionList. + +Parameters: + +Returns: + the pFunctionList or NULL +**********************************************************************/ +CK_FUNCTION_LIST_PTR +sc_get_function_list() +{ + CK_RV status; +#if defined(USE_PKCS11_DL) || defined(WIN32) + CK_RV (*gfl)(CK_FUNCTION_LIST_PTR_PTR); +#endif + if (pFunctionList) { + return pFunctionList; + } +#if defined(USE_PKCS11_DL) || defined(WIN32) + + if (!h_m_pkcs11) { + char * dllname = NULL; +#ifdef WIN32 + HKEY hkDir = NULL; + char val_dllname[512] = {"NONE"}; + LONG lval; + DWORD type; + + if (!h_m_pkcs11) { + + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); + lval = sizeof(val_dllname) -1; + if (hkDir && (RegQueryValueEx(hkDir, + "PKCS11.DLL", + 0, + &type, + val_dllname,&lval) == ERROR_SUCCESS)) { + h_m_pkcs11 = LoadLibrary(val_dllname); + } + + if (hkDir) { + RegCloseKey(hkDir); + } + if (!h_m_pkcs11) { + SCerr(SCERR_F_SCINIT,SCERR_R_NO_PKCS11_DLL); + ERR_add_error_data(2,"Name of DLL=", + dllname? dllname:"NONE"); + return NULL; + } + } + gfl = (CK_RV (*)(CK_FUNCTION_LIST_PTR *)) + GetProcAddress(h_m_pkcs11,"C_GetFunctionList"); +#else + if (!h_m_pkcs11) { + dllname = getenv("PKCS11_LIB"); + if (!dllname) { + dllname = "libDSPKCS.so"; + } + h_m_pkcs11 = dlopen("libDSPKCS.so",RTLD_LAZY); + } + if (!h_m_pkcs11) { + SCerr(SCERR_F_SCINIT,SCERR_R_NO_PKCS11_DLL); + ERR_add_error_data(2,"Name of shared library=", + dllname); + return NULL; + } + + gfl = (CK_RV(*)(CK_FUNCTION_LIST_PTR_PTR)) + dlsym(h_m_pkcs11,"C_GetFunctionList"); +#endif + if (!gfl) { + SCerr(SCERR_F_LOAD_DLL,SCERR_R_NO_PKCS11_DLL); + ERR_add_error_data(1,"Cant find C_GetFunctionList"); + return NULL; + } + } + status = (*gfl)(&pFunctionList); +#else + status = C_GetFunctionList(&pFunctionList); +#endif /* PKCS11_DYNLOAD */ + + if (status != CKR_OK) { + SCerr(SCERR_F_LOAD_DLL,SCERR_R_UNSUPPORTED); + ERR_add_error_data(1,sc_ERR_code(status)); + return NULL; + } + return pFunctionList; +} + +/********************************************************************** +Function: ERR_load_scerr_strings() + +Description: + Sets up the error tables used by SSL and adds ours + using the ERR_LIB_USER + Only the first call does anything. + +Parameters: + i should be zero the first time any of the ERR_load_.*_string functions is called and + non-zero for the rest of the calls. +Returns: +**********************************************************************/ + +int +ERR_load_scerr_strings( + int i) +{ + static int init=1; + + if (init) { + init=0; + + if (i == 0) { + SSL_load_error_strings(); + } + ERR_load_strings(ERR_USER_LIB_SCERR_NUMBER,scerr_str_functs); + ERR_load_strings(ERR_USER_LIB_SCERR_NUMBER,scerr_str_reasons); + i++; + } + return i; +} + +/********************************************************************/ +/*******************************************************************/ +/* Temporary function to reuten the error number. Should return char */ + +char * +sc_ERR_code( + CK_RV status) +{ + static char buf[256]; + + sprintf(buf,"PKCS#11 return=0x%8.8lx",status); + return buf; +} + +/********************************************************************/ + +int +sc_init( + CK_SESSION_HANDLE_PTR PsessionHandle, + char * card, + CK_SLOT_ID_PTR ppslot, + char * ppin, + CK_USER_TYPE userType, + int initialized) +{ + int rc; + CK_SLOT_ID rslot; + CK_SLOT_ID_PTR pslot; + CK_TOKEN_INFO tokeninfo; + + if (ppslot) { + pslot = ppslot; + } + else { + pslot = &rslot; + } + + if (!initialized) { + rc = sc_init_one(pslot); + if (rc) { + return rc; + } + } + +/* + rc = sc_init_info(pslot, &tokenInfo); + if (rc) { + return rc; + } +*/ + + rc = sc_init_open_login(PsessionHandle, pslot, ppin, userType); + if (rc) { + return rc; + } + return 0; +} + +/*********************************************************** +Function: sc_init_one + +Description: + get the function list pointer first. + initialize and find the slot with the card + + +***********************************************************/ +int +sc_init_one( + CK_SLOT_ID_PTR pslot) +{ + CK_RV status; + CK_SLOT_ID list[20]; + CK_SLOT_ID slot; + CK_SLOT_ID_PTR slotList = &list[0]; + CK_TOKEN_INFO tokeninfo; + CK_ULONG count = 0; + CK_C_Initialize pC_Initialize; + + if (!sc_get_function_list()) { + return SCERR_R_INITIALIZE; + } + + pC_Initialize = pFunctionList->C_Initialize; + status = (*pC_Initialize)(0); + + if (status != CKR_OK) { + SCerr(SCERR_F_SCINIT,SCERR_R_INITIALIZE); + ERR_add_error_data(1,sc_ERR_code(status)); + return SCERR_R_INITIALIZE; + } +/* + status = (*(pFunctionList->C_GetSlotList))(FALSE, NULL, &count); + if (status != CKR_OK) { + SCerr(SCERR_F_SCINIT,SCERR_R_GETSLOTLIST); + ERR_add_error_data(1,sc_ERR_code(status)); + return SCERR_R_GETSLOTLIST; + } + fprintf(stderr,"Slotlist count = %d\n",count); +*/ + count = 20; + + status = (*(pFunctionList->C_GetSlotList))(FALSE, slotList, &count); + if (status != CKR_OK) { + SCerr(SCERR_F_SCINIT,SCERR_R_GETSLOTLIST); + ERR_add_error_data(1,sc_ERR_code(status)); + return SCERR_R_GETSLOTLIST; + } + + if (count == 0) { + SCerr(SCERR_F_SCINIT,SCERR_R_OPENSESSION); + ERR_add_error_data(1,"\n No SmartCard readers found"); + return SCERR_R_OPENSESSION; + } + + /* + * need to look at all the slots. + * Maybe provide the card label then look for it + */ + + slot = list[0]; + if (pslot) { + *pslot = slot; + } + return 0; +} + + +/*************************************************************** +Function: sc_init_info + +Description: + Read the card info and print debuging + +**************************************************************/ + +int +sc_init_info( + CK_SLOT_ID_PTR pslot, + CK_TOKEN_INFO_PTR ptokenInfo) +{ + CK_RV status; + + status = (*(pFunctionList->C_GetTokenInfo))(*pslot, ptokenInfo); + if (status != CKR_OK) { + SCerr(SCERR_F_SCINIT,SCERR_R_LOGIN); + ERR_add_error_data(2, "While reading Smart Card Info", + sc_ERR_code(status)); + return SCERR_R_LOGIN; + } + + return 0; +} + +/***************************************************************** +Function: sc_init_open_login + +Description: + Open a session to the card, and login + +*****************************************************************/ + +int +sc_init_open_login( + CK_SESSION_HANDLE_PTR PsessionHandle, + CK_SLOT_ID_PTR pslot, + char * ppin, + CK_USER_TYPE userType) +{ + CK_RV status; + char * pin; + char rpin[256]; + /* could also add CKF_EXCLUSIVE_SESSION */ + int flags = + CKF_RW_SESSION | CKF_SERIAL_SESSION ; + + status = (*(pFunctionList->C_OpenSession))(*pslot, + flags, 0, NULL, PsessionHandle); + if (status != CKR_OK) { + SCerr(SCERR_F_SCINIT,SCERR_R_OPENSESSION); + ERR_add_error_data(1,sc_ERR_code(status)); + return SCERR_R_OPENSESSION; + } + + if (ppin) /* did user provide the pin? */ { + pin = ppin; + } + else { + pin = rpin; + memset(rpin,0,sizeof(rpin)); +#ifdef WIN32 + read_passphrase_win32_prompt( + (userType == CKU_USER) ? + "Smart Card User PIN:" : "Smart Card SO PIN:",0); + read_passphrase_win32(rpin,sizeof(rpin),0); +#else + des_read_pw_string(rpin,sizeof(rpin), + (userType == CKU_USER) ? + "Smart Card User PIN:" : "Smart Card SO PIN:",0); +#endif + /*DEE should test this too */ + } + + status = (*(pFunctionList->C_Login))(*PsessionHandle, userType, + (CK_CHAR_PTR)pin, strlen(pin)); + memset(rpin,0,sizeof(rpin)); + if (status != CKR_OK) { + SCerr(SCERR_F_SCINIT,SCERR_R_LOGIN); + ERR_add_error_data(1,sc_ERR_code(status)); + return SCERR_R_LOGIN; + } + + return 0; +} + + +/*********************************************************************/ +int +sc_final( + CK_SESSION_HANDLE sessionHandle) +{ + CK_RV status; + status = (*(pFunctionList->C_Logout))(sessionHandle); + status = (*(pFunctionList->C_CloseSession))(sessionHandle); + return 0; +} + + + + +/*******************************************************************/ +/* find and get data off the card */ +/*******************************************************************/ + +int +sc_get_rsa_priv_key_obj( + CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hPrivKey, + RSA ** nrkey) +{ + CK_RV sc_status; + CK_BYTE_PTR pModulus = NULL; + CK_BYTE_PTR pExponent = NULL; + CK_ATTRIBUTE template[] = { + {CKA_MODULUS, NULL_PTR, 0}, + {CKA_PUBLIC_EXPONENT, NULL_PTR, 0} + }; + RSA * rsa = NULL; + RSA_METHOD * ometh = NULL; + RSA_METHOD * nmeth = NULL; + + rsa = RSA_new(); + /* + * set to use our method for this key. i + * This will use the smart card for this key + * But to do this requires us to copy the RSA method, and + * replace two routines. This is done this way to avoid + * chanfges to the SSLeay, and since these routines are not + * exported in the Win32 DLL. + */ + + nmeth = (RSA_METHOD *)malloc(sizeof(RSA_METHOD)); + if (!nmeth) { + return 1; /* DEE need to fix */ + } + ometh = rsa->meth; + nmeth->name = ometh->name; + nmeth->rsa_pub_enc = ometh->rsa_pub_enc; + nmeth->rsa_pub_dec = ometh->rsa_pub_dec; + nmeth->rsa_priv_enc = sc_RSA_eay_private_encrypt; + nmeth->rsa_priv_dec = sc_RSA_eay_private_decrypt; + nmeth->rsa_mod_exp = ometh->rsa_mod_exp; + nmeth->bn_mod_exp = ometh->bn_mod_exp; + nmeth->init = ometh->init; + nmeth->finish = ometh->finish; + nmeth->flags = ometh->flags; + nmeth->app_data = ometh->app_data; + + rsa->meth = nmeth; + + RSA_set_ex_data(rsa,SC_RSA_EX_DATA_INDEX_SESSION,(char *) hSession); + RSA_set_ex_data(rsa,SC_RSA_EX_DATA_INDEX_OBJECT, (char *) hPrivKey); + + sc_status = (*(pFunctionList->C_GetAttributeValue)) + (hSession, hPrivKey, template, 2); + +/* + * HACK for the LITRONIC cards, as the RSA PKCS11 says + * Section 9.7.1, the card must return the Modulus + */ + if (sc_status == CKR_ATTRIBUTE_TYPE_INVALID) { + *nrkey = rsa; + return 0; + } + + if (sc_status == CKR_OK) { + pModulus = (CK_BYTE_PTR) malloc(template[0].ulValueLen); + template[0].pValue = pModulus; + pExponent = (CK_BYTE_PTR) malloc(template[1].ulValueLen); + template[1].pValue = pExponent; + + sc_status = (*(pFunctionList->C_GetAttributeValue))(hSession, + hPrivKey, + template, + 1); + } + + if (sc_status != CKR_OK) { + SCerr(SCERR_F_GET_RSA_PRIV_KEY_OBJ,SCERR_R_GETATTRVAL); + ERR_add_error_data(1,sc_ERR_code(sc_status)); + free(pModulus); + free(pExponent); + return 1; + } + + rsa->n = BN_bin2bn(pModulus,template[0].ulValueLen,NULL); + rsa->e = BN_bin2bn(pExponent,template[1].ulValueLen,NULL); + + free(pModulus); + free(pExponent); + + *nrkey = rsa; + return 0; +} +/*******************************************************************/ +int +sc_get_priv_key_obj( + CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hPrivKey, + EVP_PKEY ** npkey) +{ + int rc; + CK_RV sc_status; + CK_KEY_TYPE keyType = 0; + CK_ATTRIBUTE template[] = { + {CKA_KEY_TYPE, &keyType, sizeof(keyType)} + }; + RSA * newrkey = NULL; + EVP_PKEY * upkey=NULL; + + upkey = EVP_PKEY_new(); + + /* We should look at the attribute of the key found to + * deside if it is RSA or DSA, then call correct routine. + * For now only support RSA. + */ + + sc_status = (*(pFunctionList->C_GetAttributeValue))(hSession, + hPrivKey, template, 1); + if (sc_status != CKR_OK) { + SCerr(SCERR_F_GET_PRIV_KEY_OBJ,SCERR_R_GETATTRVAL); + ERR_add_error_data(1,sc_ERR_code(sc_status)); + return 1; + } + switch (keyType) { + case (CKK_RSA): + rc = sc_get_rsa_priv_key_obj(hSession, + hPrivKey, &newrkey); + if (rc) { + return rc; + } + EVP_PKEY_assign(upkey, EVP_PKEY_RSA, (char *)newrkey); + break; + + default: + SCerr(SCERR_F_GET_PRIV_KEY_OBJ,SCERR_R_UNSUPPORTED); + return 1; + } + + *npkey = upkey; + return 0; + +} +/*******************************************************************/ +int +sc_get_priv_key_obj_by_label( + CK_SESSION_HANDLE hSession, + char * mylabel, + EVP_PKEY ** npkey) +{ + int rc; + CK_OBJECT_HANDLE hKey; + + rc = sc_find_priv_key_obj_by_label(hSession,mylabel,&hKey); + if (rc) { + return rc; + } + return sc_get_priv_key_obj(hSession, hKey, npkey); +} + + +/*******************************************************************/ +int +sc_find_priv_key_obj_by_label( + CK_SESSION_HANDLE hSession, + char * mylabel, + CK_OBJECT_HANDLE_PTR phPrivKey) +{ + CK_RV status; + CK_KEY_TYPE keyType = CKK_RSA; + CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ATTRIBUTE template[20]; + int ai; + int li = -1; + int rc; + + ai = 0; + template[ai].type = CKA_CLASS; + template[ai].pValue = &keyClass; + template[ai].ulValueLen = sizeof(keyClass); + ai++; + + template[ai].type = CKA_TOKEN; + template[ai].pValue = &true; + template[ai].ulValueLen = sizeof(true); + ai++; + + if (strlen(mylabel)) { + template[ai].type = CKA_LABEL; + template[ai].pValue = mylabel; + template[ai].ulValueLen = strlen(mylabel) + + HACK_PKCS11_LOCAL_STRING_NULL; + li = ai; + ai++; + } + + rc = sc_find_one_obj(hSession, template, ai, phPrivKey); + /* + * we may or may not have a null as part of the name, + * so we will try again this is a modified HACK + * If we added the NULL to the test, we wont this time. + * If we did not, we will this time. + */ + if (rc && li >= 0) { + template[li].ulValueLen += 1 - 2 * HACK_PKCS11_LOCAL_STRING_NULL; + rc = sc_find_one_obj(hSession, template, ai, phPrivKey); + } + + if (rc) { + SCerr(SCERR_F_GET_PRIV_KEY_BY_LABEL,SCERR_R_FIND_FAILED); + return 1; + } + return 0; +} + +/*****************************************************************/ +int +sc_find_one_obj( + CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR template, + int ai, + CK_OBJECT_HANDLE_PTR phObject) +{ + CK_RV status; + CK_ULONG ulObjectCount; + + status = (*(pFunctionList->C_FindObjectsInit))(hSession,template,ai); + if (status != CKR_OK) { + SCerr(SCERR_F_FIND_ONE_OBJ,SCERR_R_FINDOBJINIT); + ERR_add_error_data(1,sc_ERR_code(status)); + return 1; + } + ulObjectCount = 0; + status = (*(pFunctionList->C_FindObjects))(hSession, + phObject, + 1, + &ulObjectCount); + (*(pFunctionList->C_FindObjectsFinal))(hSession); + if (status != CKR_OK) { + SCerr(SCERR_F_FIND_ONE_OBJ,SCERR_R_FINDOBJ); + ERR_add_error_data(1,sc_ERR_code(status)); + return 1; + } + + if (ulObjectCount != 1) { + SCerr(SCERR_F_FIND_ONE_OBJ,SCERR_R_FOUNDMANY); + return 1; + } + + return 0; +} + + +/*******************************************************************/ +/* find and get certificates off of card */ +/*******************************************************************/ +int +sc_get_cert_obj( + CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hCert, + X509 ** ncert) +{ + CK_RV sc_status; + CK_BYTE_PTR pCert = NULL; + unsigned char * tasn1; + CK_ATTRIBUTE template[] = { + {CKA_VALUE, NULL_PTR, 0} + }; + X509 * x509 = NULL; + + sc_status = (*(pFunctionList->C_GetAttributeValue))(hSession, + hCert, + template, + 1); + + if (sc_status == CKR_OK) { + pCert = (CK_BYTE_PTR) malloc(template[0].ulValueLen); + template[0].pValue = pCert; + } + + sc_status = (*(pFunctionList->C_GetAttributeValue))(hSession, + hCert, + template, + 1); + + if (sc_status != CKR_OK) { + SCerr(SCERR_F_GET_CERT_OBJ,SCERR_R_GETATTRVAL); + ERR_add_error_data(1,sc_ERR_code(sc_status)); + free(pCert); + return 1; + } + + tasn1 = pCert; + x509 = d2i_X509(NULL,&tasn1,template[0].ulValueLen); + if (x509 == NULL) { + SCerr(SCERR_F_GET_CERT_OBJ,SCERR_R_BAD_CERT_OBJ); + free(pCert); + return 1; + } + + *ncert = x509; + free(pCert); + return 0; +} + + +/*******************************************************************/ +int +sc_find_cert_obj_by_label( + CK_SESSION_HANDLE hSession, + char * mylabel, + CK_OBJECT_HANDLE_PTR phCert) +{ + CK_RV status; + CK_CERTIFICATE_TYPE certType = CKC_X_509; + CK_OBJECT_CLASS certClass = CKO_CERTIFICATE; + CK_BBOOL true = TRUE; + CK_BBOOL false = FALSE; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE template[20]; + int ai; + int li = -1; + int rc; + + ai = 0; + template[ai].type = CKA_CLASS; + template[ai].pValue = &certClass; + template[ai].ulValueLen = sizeof(certClass); + ai++; + + template[ai].type = CKA_CERTIFICATE_TYPE; + template[ai].pValue = &certType; + template[ai].ulValueLen = sizeof(certType); + ai++; + + template[ai].type = CKA_TOKEN; + template[ai].pValue = &true; + template[ai].ulValueLen = sizeof(true); + ai++; + + if (strlen(mylabel)) { + template[ai].type = CKA_LABEL; + template[ai].pValue = mylabel; + template[ai].ulValueLen = strlen(mylabel) + HACK_PKCS11_LOCAL_STRING_NULL; + li = ai; + ai++; + } + + rc = sc_find_one_obj(hSession, template, ai, phCert); + + /* + * we may or may not have a null as part of the name, + * so we will try again this is a modified HACK + * If we added the NULL to the test, we wont this time. + * If we did not, we will this time. + */ + if (rc && li >= 0) { + template[li].ulValueLen += 1 - 2 * HACK_PKCS11_LOCAL_STRING_NULL; + rc = sc_find_one_obj(hSession, template, ai, phCert); + } + + if (rc) { + SCerr(SCERR_F_FIND_CERT_BY_LABEL,SCERR_R_FIND_FAILED); + return 1; + } + return 0; +} + +/*******************************************************************/ +int +sc_get_cert_obj_by_label( + CK_SESSION_HANDLE hSession, + char * mylabel, + X509 ** ncert) +{ + int rc; + CK_OBJECT_HANDLE hCert; + + rc = sc_find_cert_obj_by_label(hSession,mylabel,&hCert); + if (rc) { + return rc; + } + return sc_get_cert_obj(hSession, hCert, ncert); +} + +/****************************************************************/ + +static int +sc_RSA_eay_private_encrypt( + int flen, + unsigned char * from, + unsigned char * to, + RSA * rsa, + int padding) +{ + CK_ULONG ulsiglen; + CK_MECHANISM_PTR pMech = NULL; + CK_MECHANISM m_rsa_pkcs = {CKM_RSA_PKCS, 0,0}; + CK_MECHANISM m_rsa_raw = {CKM_RSA_X_509, 0,0}; + CK_RV ck_status; + CK_SESSION_HANDLE hSession; + CK_OBJECT_HANDLE hObject; + + hSession = (CK_SESSION_HANDLE )RSA_get_ex_data( + rsa, + SC_RSA_EX_DATA_INDEX_SESSION); + + hObject = (CK_OBJECT_HANDLE) RSA_get_ex_data( + rsa, + SC_RSA_EX_DATA_INDEX_OBJECT); + + switch (padding) { + case RSA_PKCS1_PADDING: + pMech = &m_rsa_pkcs; + break; + case RSA_NO_PADDING: + pMech = &m_rsa_raw; + break; + case RSA_SSLV23_PADDING: + default: + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,RSA_R_UNKNOWN_PADDING_TYPE); + } + + if (pMech == NULL) { + return 0; + } + + ck_status = (*(pFunctionList->C_SignInit))(hSession, pMech, hObject); + if (ck_status != CKR_OK) { + SCerr(SCERR_F_RSA_ENCRYPT,SCERR_R_SIGNINIT); + ERR_add_error_data(1,sc_ERR_code(ck_status)); + return 0; + } + + ck_status = (*(pFunctionList->C_Sign))(hSession, + from, flen, to, &ulsiglen); + if (ck_status != CKR_OK) { + SCerr(SCERR_F_RSA_ENCRYPT,SCERR_R_SIGN); + ERR_add_error_data(1,sc_ERR_code(ck_status)); + return 0; + } + + return ulsiglen; +} + +/***************************************************************/ + +static int +sc_RSA_eay_private_decrypt( + int flen, + unsigned char * from, + unsigned char * to, + RSA * rsa, + int padding) +{ + CK_ULONG ulsiglen; + CK_MECHANISM_PTR pMech = NULL; + CK_MECHANISM m_rsa_pkcs = {CKM_RSA_PKCS, 0,0}; + CK_MECHANISM m_rsa_raw = {CKM_RSA_X_509, 0,0}; + CK_RV ck_status; + CK_SESSION_HANDLE hSession; + CK_OBJECT_HANDLE hObject; + + hSession = (CK_SESSION_HANDLE )RSA_get_ex_data( + rsa, + SC_RSA_EX_DATA_INDEX_SESSION); + + hObject = (CK_OBJECT_HANDLE) RSA_get_ex_data( + rsa, + SC_RSA_EX_DATA_INDEX_OBJECT); + + switch (padding) { + case RSA_PKCS1_PADDING: + pMech = &m_rsa_pkcs; + break; + case RSA_NO_PADDING: + pMech = &m_rsa_raw; + break; + case RSA_SSLV23_PADDING: + default: + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,RSA_R_UNKNOWN_PADDING_TYPE); + } + + if (pMech == NULL) { + return 0; + } + + ulsiglen = BN_num_bytes(rsa->n); + + ck_status = (*(pFunctionList->C_SignRecoverInit))(hSession, + pMech, hObject); + if (ck_status != CKR_OK) { + SCerr(SCERR_F_RSA_DECRYPT,SCERR_R_SIGNRECINIT); + ERR_add_error_data(1,sc_ERR_code(ck_status)); + return 0; + } + + ck_status = (*(pFunctionList->C_SignRecover))(hSession, + from, + flen, + to, + &ulsiglen); + if (ck_status != CKR_OK) { + SCerr(SCERR_F_RSA_DECRYPT,SCERR_R_SIGNREC); + ERR_add_error_data(1,sc_ERR_code(ck_status)); + return 0; + } + return ulsiglen; +} +#endif /*USE_PKCS11*/ + + diff --git a/emi.canl.canl-c/src/proxy/scutils.h b/emi.canl.canl-c/src/proxy/scutils.h new file mode 100644 index 0000000..1b0b311 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/scutils.h @@ -0,0 +1,251 @@ +/********************************************************************** +scutils.h: + +Description: + This header file used internally for smart card access via PKCS11 + For windows we can dynamicly load, and so PKCS#11 support + can allways be compiled, as we now have the RSA header files + included from the PKCS#11 2.01 version + + +**********************************************************************/ + +#ifndef VOMS_SCUTILS_H +#define VOMS_SCUTILS_H + +/********************************************************************** + Include header files +**********************************************************************/ +#ifndef NO_GSSAPI_CONFIG_H +#include "gssapi_config.h" +#endif + +#include +#include "ssl.h" +#include "err.h" +#include "bio.h" +#include "pem.h" +#include "x509.h" +#include "stack.h" +#include "evp.h" +#include "rsa.h" + +#include "pkcs11.h" + +#ifdef USE_TYPEMAP +#include "typemap.h" +#endif + +/********************************************************************** + Define constants +**********************************************************************/ +/* RSA PKCS#11 says local strings donot include the null, + * but examples do. Litronics writes the null in their labels + * and expect them when formating. + * The following will be added when writing a label or + * other local string which might have this problem. + * If other cards dont require, or this gets fixed, + * set this to 0 + * + * This was with Litronic before NetSign 2.0 + * + * We have added code to try with and without the null, + * So set this to 0 for now. + */ +#define HACK_PKCS11_LOCAL_STRING_NULL 0 + +/* + * We need to store the session and object handles with the key. + * In order to avoid changes to SSLeay, for the RSA structire, + * we will use two of the ex_data fields, by grabing 3 and 4. + * This may be a problem in future versions. + * These are used by the _get_ key routines when creating + * the key structure below, and by the sc_RSA_eay routines when + * they go to use the key. + */ + +#define SC_RSA_EX_DATA_INDEX_SESSION 3 +#define SC_RSA_EX_DATA_INDEX_OBJECT 4 + + +/* Location where the SCERR library will be stored */ +#define ERR_USER_LIB_SCERR_NUMBER ((ERR_LIB_USER) + 1) + +/* + * Use the SSLeay error facility with the ERR_LIB_USER + */ + +#define SCerr(f,r) ERR_PUT_error(ERR_USER_LIB_SCERR_NUMBER,(f),(r),__FILE__,__LINE__) + +/* + * defines for function codes our minor error codes + */ + +#define SCERR_F_RSA_ENCRYPT 100 +#define SCERR_F_RSA_DECRYPT 101 +#define SCERR_F_SCINIT 102 +#define SCERR_F_CREATE_DATA_OBJ 103 +#define SCERR_F_CREATE_CERT_OBJ 104 +#define SCERR_F_CREATE_RSA_PRIV_KEY_OBJ 105 +#define SCERR_F_CREATE_PRIV_KEY_OBJ 106 +#define SCERR_F_GET_RSA_PRIV_KEY_OBJ 107 +#define SCERR_F_GET_PRIV_KEY_OBJ 108 +#define SCERR_F_GET_PRIV_KEY_BY_LABEL 109 +#define SCERR_F_GET_CERT_OBJ 110 +#define SCERR_F_FIND_ONE_OBJ 111 +#define SCERR_F_FIND_CERT_BY_LABEL 112 +#define SCERR_F_LOAD_DLL 113 + +/* + * defines for reasons + */ + +#define SCERR_R_BASE 1500 + +#define SCERR_R_PKCS11_ERROR SCERR_R_BASE + 1 +#define SCERR_R_SIGNINIT SCERR_R_BASE + 2 +#define SCERR_R_SIGN SCERR_R_BASE + 3 +#define SCERR_R_SIGNRECINIT SCERR_R_BASE + 4 +#define SCERR_R_SIGNREC SCERR_R_BASE + 5 +#define SCERR_R_INITIALIZE SCERR_R_BASE + 6 +#define SCERR_R_GETSLOTLIST SCERR_R_BASE + 7 +#define SCERR_R_OPENSESSION SCERR_R_BASE + 8 +#define SCERR_R_LOGIN SCERR_R_BASE + 9 +#define SCERR_R_CREATEOBJ SCERR_R_BASE + 10 +#define SCERR_R_UNSUPPORTED SCERR_R_BASE + 11 +#define SCERR_R_GETATTRVAL SCERR_R_BASE + 12 +#define SCERR_R_FINDOBJINIT SCERR_R_BASE + 13 +#define SCERR_R_FINDOBJ SCERR_R_BASE + 14 +#define SCERR_R_FOUNDMANY SCERR_R_BASE + 15 +#define SCERR_R_BAD_CERT_OBJ SCERR_R_BASE + 16 +#define SCERR_R_FIND_FAILED SCERR_R_BASE + 17 +#define SCERR_R_NO_PKCS11_DLL SCERR_R_BASE + 18 +/* NOTE: Reason codes are limited to <4096 by openssl error handler */ + +/********************************************************************** + Type definitions +**********************************************************************/ + +/********************************************************************** + Global variables +*********************************************************************/ + +/* The pFunctionList is a pointer to the PKCS11 list + * of functions which is in the lib or DLL. + * It is initialized once on the first call to the + * sc_init() by sc_get_funct_list() + */ + +extern CK_FUNCTION_LIST_PTR pFunctionList; + +/********************************************************************** + Function prototypes +**********************************************************************/ +int +ERR_load_scerr_strings(int i); + +char * +sc_ERR_code(CK_RV status); + +CK_FUNCTION_LIST_PTR +sc_get_function_list(); + +int +sc_init(CK_SESSION_HANDLE_PTR PsessionHandle, + char *card, + CK_SLOT_ID_PTR pslot, + char * ppin, + CK_USER_TYPE userType, + int initialized); + +int +sc_init_one(CK_SLOT_ID_PTR pslot); + +int +sc_init_info(CK_SLOT_ID_PTR pslot, + CK_TOKEN_INFO_PTR ptokenInfo); + +int +sc_init_open_login(CK_SESSION_HANDLE_PTR PsessionHandle, + CK_SLOT_ID_PTR pslot, + char * ppin, + CK_USER_TYPE userType); + +int +sc_final(CK_SESSION_HANDLE sessionHandle); + + +int +sc_create_data_obj(CK_SESSION_HANDLE sessionHandle, + char *mylabel, + char *myvalue, + int mylen); + +int +sc_create_rsa_priv_key_obj(CK_SESSION_HANDLE sessionHandle, + char *mylabel, + RSA *rkey); + +int +sc_create_priv_key_obj(CK_SESSION_HANDLE sessionHandle, + char *mylabel, + EVP_PKEY *key); + +int +sc_create_cert_obj(CK_SESSION_HANDLE sessionHandle, + char *mylabel, + X509 *ucert); + +/**********************/ +int +sc_get_rsa_priv_key_obj(CK_SESSION_HANDLE sessionHandle, + CK_OBJECT_HANDLE hPrivKey, + RSA ** nrkey); + +int +sc_get_priv_key_obj(CK_SESSION_HANDLE sessionHandle, + CK_OBJECT_HANDLE hPrivKey, + EVP_PKEY ** nkey); + +int +sc_get_priv_key_obj_by_label(CK_SESSION_HANDLE sessionHandle, + char *mylabel, + EVP_PKEY ** nkey); + +int +sc_get_cert_obj_by_label(CK_SESSION_HANDLE sessionHandle, + char *mylabel, + X509 ** ncert); + +int +sc_find_one_obj(CK_SESSION_HANDLE sessionHandle, + CK_ATTRIBUTE_PTR template, + int ai, + CK_OBJECT_HANDLE_PTR phObject); + +int +sc_find_priv_key_obj_by_label(CK_SESSION_HANDLE sessionHandle, + char * mylabel, + CK_OBJECT_HANDLE_PTR phPrivKey); + +int +sc_find_cert_obj_by_label(CK_SESSION_HANDLE hSession, + char * mylabel, + CK_OBJECT_HANDLE_PTR phCert); + +int +sc_find_cert_obj_by_subject(CK_SESSION_HANDLE hSession, + X509_NAME * x509name, + CK_OBJECT_HANDLE_PTR phCert); + + +/************************************************************************/ +/* replacement RSA_PKCS1_SSLeay routines which will use the key on the */ +/* smart card We have our own method which will call PKCS11 */ +/* These are in sc_rsa_ssleay.c */ +/************************************************************************/ + +RSA_METHOD * sc_RSA_PKCS1_SSLeay(); + + +#endif /* _SCUTILS_H */ diff --git a/emi.canl.canl-c/src/proxy/signing_policy.l b/emi.canl.canl-c/src/proxy/signing_policy.l new file mode 100644 index 0000000..89fb20f --- /dev/null +++ b/emi.canl.canl-c/src/proxy/signing_policy.l @@ -0,0 +1,68 @@ +%{ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" +#include +#include + +#include + +#include "parsertypes.h" +#include "signing_policy.h" +extern char *strndup(const char*, size_t); +%} + +%x SINGLE_QUOTED +%x DOUBLE_QUOTED + +%option reentrant +%option noyywrap +%option prefix="signing" +%option bison-bridge + +%% + +#.* /* ignore comments */ +\' BEGIN(SINGLE_QUOTED); + +[^']*\' yytext[strlen(yytext)-1]='\0'; yylval_param->string = yytext; BEGIN(INITIAL); return SUBJECTS; + +\" BEGIN(DOUBLE_QUOTED); +[^"]*\" yytext[strlen(yytext)-1]='\0'; yylval_param->string = yytext; BEGIN(INITIAL); return SUBJECTS; + + +cond_subjects return COND_SUBJECTS; +cond_banned_subjects return COND_BANNED; +globus return GLOBUS; +pos_rights return POS_RIGHTS; +neg_rights return NEG_RIGHTS; +CA\:sign return CA_SIGN; +access_id_CA return ACCESS_ID_CA; +access_id_ANYBODY return ACCESS_ID_ANYBODY; +X509 return X509; + +\n +. + diff --git a/emi.canl.canl-c/src/proxy/signing_policy.y b/emi.canl.canl-c/src/proxy/signing_policy.y new file mode 100644 index 0000000..93fab4f --- /dev/null +++ b/emi.canl.canl-c/src/proxy/signing_policy.y @@ -0,0 +1,195 @@ +%{ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * Valerio Venturi - Valerio.Venturi@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +#include "config.h" +#include +#include +#include +#include + +#include "parsertypes.h" +#include "listfunc.h" + +char **parse_subjects(char *string); +void signingerror(void *policies, void *scanner, char const *msg); +%} + +%error-verbose +%pure-parser +%name-prefix="signing" +%parse-param {struct policy ***policies} +%parse-param {void *scanner} +%lex-param {void *scanner} + +%union{ + char *string; + struct condition *cond; + struct policy *policy; + void *array; +} + +%token SUBJECTS +%token COND_SUBJECTS +%token COND_BANNED +%token GLOBUS +%token POS_RIGHTS +%token NEG_RIGHTS +%token CA_SIGN +%token ACCESS_ID_CA +%token ACCESS_ID_ANYBODY +%token X509 + +%type eacl_entry +%type access_identity +%type realcondition +%type restrictions +%type access_identities +%% + +eacl: eacl_entry { *policies = (struct policy **)listadd((char**)(*policies), (char*)($1)); } +| eacl eacl_entry { *policies = (struct policy **)listadd((char**)(*policies), (char*)($2)); } + +eacl_entry: access_identities POS_RIGHTS GLOBUS CA_SIGN restrictions { + if ($1) { + $$->conds = (struct condition**)($5); + } + $$ = $1; +} +| access_identities NEG_RIGHTS GLOBUS CA_SIGN restrictions { + /* Ignore this. Globus does. */ + free($1); + $$ = NULL; +} + +access_identities: access_identity { + $$ = $1; +} + +restrictions: realcondition { + $$ = listadd(NULL, (char*)($1)); +} +| realcondition restrictions { + $$ = listadd($2, (char*)($1)); +} + + +access_identity: ACCESS_ID_CA X509 SUBJECTS { + $$ = (struct policy *)calloc(1, sizeof(struct policy)); + + if ($$) { + char **subjects = parse_subjects($3); + $$->caname = strdup(subjects[0]); + free(subjects); + $$->type = TYPE_SIGNING; + } + + if ($$ && !$$->caname) { + free($$); + $$ = NULL; + } +} +| ACCESS_ID_ANYBODY { + $$ = (struct policy *)calloc(1, sizeof(struct policy)); +} + +realcondition: COND_SUBJECTS GLOBUS SUBJECTS { + $$ = (struct condition*)malloc(sizeof(struct condition)); + if ($$) { + $$->positive = 1; + $$->original = strdup($3); + $$->subjects = parse_subjects($$->original); + if (!$$->subjects) { + free($$->original); + free($$); + $$ = NULL; + } + } +} +| COND_BANNED GLOBUS SUBJECTS { + $$ = (struct condition*)malloc(sizeof(struct condition)); + + if ($$) { + $$->positive = 0; + $$->original = strdup($3); + $$->subjects = parse_subjects($$->original); + if (!$$->subjects) { + free($$->original); + free($$); + $$ = NULL; + } + } +} +; + +%% + +char **parse_subjects(char *string) +{ + char **list = NULL; + char divider; + + if (!string) + return NULL; + + do { + divider = string[0]; + + if (divider == '\'' || divider == '"') { + char *end = strchr(string + 1, divider); + if (!end) + return list; + *end = '\0'; + + list = (char**)listadd(list, string+1); + string = ++end; + while (isspace(*string)) + string++; + } + else if (divider == '\0') + break; + else { + list = (char**)listadd(list, string); + string += strlen(string); + } + } while (string && string[0] != '\0'); + + return list; +} + +#if 0 +int main() +{ + signingdebug = 1; + void **arg = NULL; + void *scanner=NULL; + signinglex_init(&scanner); + signingset_debug(1, scanner); + return signingparse(arg, scanner); +} +#endif +void signingerror(UNUSED(void *policies), UNUSED(void *scanner), UNUSED(char const *msg)) +{ +} diff --git a/emi.canl.canl-c/src/proxy/sslutils.c b/emi.canl.canl-c/src/proxy/sslutils.c new file mode 100644 index 0000000..9dd7d09 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/sslutils.c @@ -0,0 +1,3968 @@ +/********************************************************************* + * + * Authors: Valerio Venturi - Valerio.Venturi@cnaf.infn.it + * Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) 2002-2009 INFN-CNAF on behalf of the EU DataGrid + * and EGEE I, II and III + * For license conditions see LICENSE file or + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +/********************************************************************** + +sslutils.c + +Description: + Routines used internally to implement delegation and proxy + certificates for use with Globus The same file is also used + for the non-exportable sslk5 which allows Kerberos V5 to + accept SSLv3 with certificates as proof of identiy and + issue a TGT. + +**********************************************************************/ + +/********************************************************************** + Include header files +**********************************************************************/ +#define _GNU_SOURCE + +//#include "config.h" +//#include "replace.h" +#include "myproxycertinfo.h" +#include "sslutils.h" +#include "parsertypes.h" +#include "doio.h" +//#include "data.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef DEFAULT_SECURE_TMP_DIR +#ifndef WIN32 +#define DEFAULT_SECURE_TMP_DIR "/tmp" +#else +#define DEFAULT_SECURE_TMP_DIR "c:\\tmp" +#endif +#endif + +#ifndef WIN32 +#define FILE_SEPERATOR "/" +#else +#define FILE_SEPERATOR "\\" +#endif + +#ifdef WIN32 +#include "winglue.h" +#include +#else +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "openssl/buffer.h" +#include "openssl/crypto.h" + +#include "openssl/objects.h" +#include "openssl/asn1.h" +#include "openssl/evp.h" +#include "openssl/pkcs12.h" + +#include "openssl/rsa.h" +#include "openssl/rand.h" +#if SSLEAY_VERSION_NUMBER >= 0x0090581fL +#include "openssl/x509v3.h" +#endif + +#ifndef X509_V_ERR_INVALID_PURPOSE +#define X509_V_ERR_INVALID_PURPOSE X509_V_ERR_CERT_CHAIN_TOO_LONG +#endif + +#ifdef USE_PKCS11 +#include "scutils.h" +#endif + +static int fix_add_entry_asn1_set_param = 0; + + +#define V1_ROOT (EXFLAG_V1|EXFLAG_SS) +#define ku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) +#define xku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage))) +#define ns_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) + +static X509_NAME *make_DN(const char *dnstring); + + +extern int restriction_evaluate(STACK_OF(X509) *chain, struct policy **namespaces, + struct policy **signings); +extern void voms_free_policies(struct policy **policies); +extern int read_pathrestriction(STACK_OF(X509) *chain, char *path, + struct policy ***namespaces, + struct policy ***signings); + +static int check_critical_extensions(X509 *cert, int itsaproxy); + +/********************************************************************** + Type definitions +**********************************************************************/ + +/********************************************************************** + Module specific prototypes +**********************************************************************/ + +/********************************************************************** + Define module specific variables +**********************************************************************/ +static ERR_STRING_DATA prxyerr_str_functs[]= +{ + {ERR_PACK(0,PRXYERR_F_PROXY_GENREQ ,0),"proxy_genreq"}, + {ERR_PACK(0,PRXYERR_F_PROXY_SIGN ,0),"proxy_sign"}, + {ERR_PACK(0,PRXYERR_F_VERIFY_CB ,0),"verify_callback"}, + {ERR_PACK(0,PRXYERR_F_PROXY_TMP ,0),"proxy_marshal_tmp"}, + {ERR_PACK(0,PRXYERR_F_INIT_CRED ,0),"proxy_init_cred"}, + {ERR_PACK(0,PRXYERR_F_LOCAL_CREATE, 0),"proxy_local_create"}, + {ERR_PACK(0,PRXYERR_F_CB_NO_PW, 0),"proxy_pw_cb"}, + {ERR_PACK(0,PRXYERR_F_GET_CA_SIGN_PATH, 0),"get_ca_signing_policy_path"}, + {ERR_PACK(0,PRXYERR_F_PROXY_SIGN_EXT ,0),"proxy_sign_ext"}, + {ERR_PACK(0,PRXYERR_F_PROXY_CHECK_SUBJECT_NAME,0), + "proxy_check_subject_name"}, + {ERR_PACK(0,PRXYERR_F_PROXY_CONSTRUCT_NAME ,0),"proxy_construct_name"}, + {0,NULL}, +}; + +static ERR_STRING_DATA prxyerr_str_reasons[]= +{ + {PRXYERR_R_PROCESS_PROXY_KEY, "processing proxy key"}, + {PRXYERR_R_PROCESS_REQ, "creating proxy req"}, + {PRXYERR_R_PROCESS_SIGN, "while signing proxy req"}, + {PRXYERR_R_MALFORM_REQ, "malformed proxy req"}, + {PRXYERR_R_SIG_VERIFY, "proxy req signature verification error"}, + {PRXYERR_R_SIG_BAD, "proxy req signature does not match"}, + {PRXYERR_R_PROCESS_PROXY, "processing user proxy cert"}, + {PRXYERR_R_PROXY_NAME_BAD, "proxy name does not match"}, + {PRXYERR_R_PROCESS_SIGNC, "while signing proxy cert"}, + {PRXYERR_R_BAD_PROXY_ISSUER, "proxy can only be signed by user"}, + {PRXYERR_R_SIGN_NOT_CA ,"user cert not signed by CA"}, + {PRXYERR_R_PROBLEM_PROXY_FILE ,"problems creating proxy file"}, + {PRXYERR_R_PROCESS_KEY, "processing key"}, + {PRXYERR_R_PROCESS_CERT, "processing cert"}, + {PRXYERR_R_PROCESS_CERTS, "unable to access trusted certificates in:"}, + {PRXYERR_R_PROCESS_PROXY, "processing user proxy cert"}, + {PRXYERR_R_NO_TRUSTED_CERTS, "check X509_CERT_DIR and X509_CERT_FILE"}, + {PRXYERR_R_PROBLEM_KEY_FILE, "bad file system permissions on private key\n" + " key must only be readable by the user"}, + {PRXYERR_R_SERVER_ZERO_LENGTH_KEY_FILE, "system key file is empty"}, + {PRXYERR_R_USER_ZERO_LENGTH_KEY_FILE, "user private key file is empty"}, + {PRXYERR_R_PROBLEM_SERVER_NOKEY_FILE, "system key cannot be accessed"}, + {PRXYERR_R_PROBLEM_USER_NOKEY_FILE, "user private key cannot be accessed"}, + {PRXYERR_R_PROBLEM_SERVER_NOCERT_FILE, "system certificate not found"}, + {PRXYERR_R_PROBLEM_USER_NOCERT_FILE, "user certificate not found"}, + {PRXYERR_R_INVALID_CERT, "no certificate in file"}, + {PRXYERR_R_REMOTE_CRED_EXPIRED, "remote certificate has expired"}, + {PRXYERR_R_USER_CERT_EXPIRED, "user certificate has expired"}, + {PRXYERR_R_SERVER_CERT_EXPIRED, "system certificate has expired"}, + {PRXYERR_R_PROXY_EXPIRED, "proxy expired: run grid-proxy-init or wgpi first"}, + {PRXYERR_R_NO_PROXY, "no proxy credentials: run grid-proxy-init or wgpi first"}, + {PRXYERR_R_CRL_SIGNATURE_FAILURE, "invalid signature on a CRL"}, + {PRXYERR_R_CRL_NEXT_UPDATE_FIELD, "invalid nextupdate field in CRL"}, + {PRXYERR_R_CRL_HAS_EXPIRED, "outdated CRL found, revoking all certs till you get new CRL"}, + {PRXYERR_R_CERT_REVOKED, "certificate revoked per CRL"}, + {PRXYERR_R_NO_HOME, "can't determine HOME directory"}, + {PRXYERR_R_KEY_CERT_MISMATCH, "user key and certificate don't match"}, + {PRXYERR_R_WRONG_PASSPHRASE, "wrong pass phrase"}, + {PRXYERR_R_CA_POLICY_VIOLATION, "remote certificate CA signature not allowed by policy"}, + {PRXYERR_R_CA_POLICY_ERR,"no matching CA found in file for remote certificate"}, + {PRXYERR_R_CA_NOFILE,"could not find CA policy file"}, + {PRXYERR_R_CA_NOPATH,"could not determine path to CA policy file"}, + {PRXYERR_R_CA_POLICY_RETRIEVE, "CA policy retrieve problems"}, + {PRXYERR_R_CA_POLICY_PARSE, "CA policy parse problems"}, + {PRXYERR_R_CA_UNKNOWN,"remote certificate signed by unknown CA"}, + {PRXYERR_R_PROBLEM_CLIENT_CA, "problems getting client_CA list"}, + {PRXYERR_R_CB_NO_PW, "no proxy credentials: run grid-proxy-init or wgpi first"}, + {PRXYERR_R_CB_CALLED_WITH_ERROR,"certificate failed verify:"}, + {PRXYERR_R_CB_ERROR_MSG, "certificate:"}, + {PRXYERR_R_CLASS_ADD_OID,"can't find CLASS_ADD OID"}, + {PRXYERR_R_CLASS_ADD_EXT,"problem adding CLASS_ADD Extension"}, + {PRXYERR_R_DELEGATE_VERIFY,"problem verifiying the delegate extension"}, + {PRXYERR_R_EXT_ADD,"problem adding extension"}, + {PRXYERR_R_DELEGATE_CREATE,"problem creating delegate extension"}, + {PRXYERR_R_DELEGATE_COPY,"problem copying delegate extension to proxy"}, + {PRXYERR_R_BUFFER_TOO_SMALL,"buffer too small"}, + {PRXYERR_R_CERT_NOT_YET_VALID,"remote certificate not yet valid"}, + {PRXYERR_R_LOCAL_CA_UNKNOWN,"cannot find CA certificate for local credential"}, + {PRXYERR_R_OUT_OF_MEMORY,"out of memory"}, + {PRXYERR_R_BAD_ARGUMENT,"bad argument"}, + {PRXYERR_R_BAD_MAGIC,"bad magic number"}, + {PRXYERR_R_UNKNOWN_CRIT_EXT,"unable to handle critical extension"}, + {0,NULL} +}; + +int my_txt2nid(char *name) +{ + ASN1_OBJECT *obj = OBJ_txt2obj(name,1); + int nid = OBJ_obj2nid(obj); + ASN1_OBJECT_free(obj); + + return nid; +} + +/********************************************************************* +Function: X509_NAME_cmp_no_set + +Description: + To circumvent a bug with adding X509_NAME_ENTRIES + with the wrong "set", we will compare names without + the set. + This is a temporary fix which will be removed when we + fix the creation of the names using the correct sets. + This is only being done this way for some compatability + while installing the these fixes. + This fix is needed in all previous versions of Globus. + +Parameters: + same as X509_NAME_cmp +Returns : + same as X509_NAME_cmp +********************************************************************/ +static int +X509_NAME_cmp_no_set( + X509_NAME * a, + X509_NAME * b) +{ + int i; + int j; + X509_NAME_ENTRY * na; + X509_NAME_ENTRY * nb; + + if (sk_X509_NAME_ENTRY_num(a->entries) != + sk_X509_NAME_ENTRY_num(b->entries)) + { + return(sk_X509_NAME_ENTRY_num(a->entries) - + sk_X509_NAME_ENTRY_num(b->entries)); + } + + for (i=sk_X509_NAME_ENTRY_num(a->entries)-1; i>=0; i--) + { + na = sk_X509_NAME_ENTRY_value(a->entries,i); + nb = sk_X509_NAME_ENTRY_value(b->entries,i); + j = na->value->length-nb->value->length; + + if (j) + { + return(j); + } + + j = memcmp(na->value->data, + nb->value->data, + na->value->length); + if (j) + { + return(j); + } + } + + /* We will check the object types after checking the values + * since the values will more often be different than the object + * types. */ + for (i=sk_X509_NAME_ENTRY_num(a->entries)-1; i>=0; i--) + { + na = sk_X509_NAME_ENTRY_value(a->entries,i); + nb = sk_X509_NAME_ENTRY_value(b->entries,i); + j = OBJ_cmp(na->object,nb->object); + + if (j) + { + return(j); + } + } + return(0); +} + +#ifdef WIN32 +/********************************************************************* +Function: getuid, getpid + +Descriptions: + For Windows95, WIN32, we don't have these, so we will default + to using uid 0 and pid 0 Need to look at this better for NT. +******************************************************************/ +static unsigned long +getuid() +{ + return 0; +} + +static int +getpid() +{ + return 0; +} + +#endif /* WIN32 */ + + +#if SSLEAY_VERSION_NUMBER < 0x0900 + +/********************************************************************** +Function: ERR_add_error_data() + +Description: + Dummy routine only defined if running with SSLeay-0.8.x + this feature was introduced with SSLeay-0.9.0 + +Parameters: + +Returns: +**********************************************************************/ +void PRIVATE +ERR_add_error_data( VAR_PLIST( int, num )) + VAR_ALIST +{ + VAR_BDEFN(args, int, num); +} + +/********************************************************************** +Function: ERR_get_error_line_data() + +Description: + Dummy routine only defined if running with SSLeay-0.8.x + this feature was introduced with SSLeay-0.9.0. We will + simulate it for 0.8.1 + +Parameters: + +Returns: +**********************************************************************/ +unsigned long PRIVATE +ERR_get_error_line_data( + char ** file, + int * line, + char ** data, + int * flags) +{ + if (data) + { + *data = ""; + } + + if (flags) + { + *flags = 0; + } + + return (ERR_get_error_line(file, line)); +} + +#endif + +/********************************************************************** +Function: ERR_set_continue_needed() + +Description: + Sets state information which error display routines can use to + determine if the error just added is enough information to describe + the error or if further error information need displayed. + (By default gss_display_status will only show one user level error) + + note: This function must be called after (or instead of) the ssl add error + data functions. + +Parameters: + +Returns: +**********************************************************************/ + +void PRIVATE +ERR_set_continue_needed(void) +{ + ERR_STATE *es; + es = ERR_get_state(); + es->err_data_flags[es->top] = + es->err_data_flags[es->top] | ERR_DISPLAY_CONTINUE_NEEDED; +} + +/********************************************************************** +Function: ERR_load_prxyerr_strings() + +Description: + Sets up the error tables used by SSL and adds ours + using the ERR_LIB_USER + Only the first call does anything. + Will also add any builtin objects for SSLeay. + +Parameters: + i should be zero the first time one of the ERR_load functions + is called and non-zero for each additional call. + +Returns: +**********************************************************************/ + +int PRIVATE +ERR_load_prxyerr_strings( + int i) +{ + static int init = 1; + struct stat stx; + clock_t cputime; +#if SSLEAY_VERSION_NUMBER >= 0x00904100L + const char * randfile; +#else + char * randfile; +#endif +#if SSLEAY_VERSION_NUMBER >= 0x0090581fL + char * egd_path; +#endif + char buffer[200]; + + if (init) + { + init = 0; + +#ifndef RAND_DO_NOT_USE_CLOCK + clock(); +#endif + if (i == 0) + { + SSL_load_error_strings(); + } + + OBJ_create("1.3.6.1.4.1.3536.1.1.1.1","CLASSADD","ClassAdd"); + OBJ_create("1.3.6.1.4.1.3536.1.1.1.2","DELEGATE","Delegate"); + OBJ_create("1.3.6.1.4.1.3536.1.1.1.3","RESTRICTEDRIGHTS", + "RestrictedRights"); + OBJ_create("0.9.2342.19200300.100.1.1","USERID","userId"); + + ERR_load_strings(ERR_USER_LIB_PRXYERR_NUMBER,prxyerr_str_functs); + ERR_load_strings(ERR_USER_LIB_PRXYERR_NUMBER,prxyerr_str_reasons); + + /* + * We need to get a lot of randomness for good security + * OpenSSL will use /dev/urandom (if available), + * uid, time, and gid. + * + * If user has RANDFILE set, or $HOME/.rnd + * load it for extra random seed. + * This may also not be enough, so we will also add in + * the time it takes to run this routine, which includes + * reading the randfile. + * Later we will also add in some keys and some stats + * if we have them. + * look for RAND_add in this source file. + * + * Other methods we could use: + * * Librand from Don Mitchell and Matt Blaze + * * Doing a netstat -in + * * some form of pstat + * But /dev/random and/or egd should be enough. + */ + + randfile = RAND_file_name(buffer,200); + + if (randfile) + { + RAND_load_file(randfile,1024L*1024L); + } + +#if SSLEAY_VERSION_NUMBER >= 0x0090581fL + /* + * Try to use the Entropy Garthering Deamon + * See the OpenSSL crypto/rand/rand_egd.c + */ + egd_path = getenv("EGD_PATH"); + if (egd_path == NULL) + { + egd_path = "/etc/entropy"; + } + RAND_egd(egd_path); +#endif + + /* if still not enough entropy*/ + if (RAND_status() == 0) + { + stat("/tmp",&stx); /* get times /tmp was modified */ + RAND_add((void*)&stx,sizeof(stx),16); + } + +#ifndef RAND_DO_NOT_USE_CLOCK + cputime = clock(); + RAND_add((void*)&cputime, sizeof(cputime),8); +#endif + + i++; +#ifdef USE_PKCS11 + i = ERR_load_scerr_strings(i); +#endif + + } + return i; +} + +/********************************************************************** +Function: checkstat() +Description: check the status of a file +Parameters: +Returns: + 0 pass all the following tests + 1 does not exist + 2 not owned by user + 3 readable by someone else + 4 zero length +**********************************************************************/ +static int checkstat(const char* filename) +{ + struct stat stx; + + if (stat(filename,&stx) != 0) + { + return 1; + } + + /* + * use any stat output as random data, as it will + * have file sizes, and last use times in it. + */ + RAND_add((void*)&stx,sizeof(stx),2); + +#if !defined(WIN32) && !defined(TARGET_ARCH_CYGWIN) + if (stx.st_uid != getuid()) + { + return 2; + } + + if (stx.st_mode & 066) + { + return 3; + } + +#endif /* !WIN32 && !TARGET_ARCH_CYGWIN */ + + if (stx.st_size == 0) + { + return 4; + } + return 0; + +} + +/********************************************************************** +Function: proxy_load_user_proxy() + +Description: + Given the user_proxy file, skip the first cert, + and add any additional certs to the cert_chain. + These must be additional proxies, or the user's cert + which signed the proxy. + This is based on the X509_load_cert_file routine. + +Parameters: + +Returns: +**********************************************************************/ + +int PRIVATE +proxy_load_user_proxy( + STACK_OF(X509) * cert_chain, + const char * file) +{ + + int ret = -1; + BIO * in = NULL; + int count=0; + X509 * x = NULL; + + if (file == NULL) + return(1); + + in = BIO_new(BIO_s_file()); + + + if ((in == NULL) || (BIO_read_filename(in,file) <= 0)) + { + X509err(PRXYERR_F_PROXY_LOAD, PRXYERR_R_PROCESS_PROXY); + goto err; + } + + for (;;) + { + x = PEM_read_bio_X509(in,NULL, OPENSSL_PEM_CB(NULL,NULL)); + if (x == NULL) + { + if ((ERR_GET_REASON(ERR_peek_error()) == + PEM_R_NO_START_LINE) && (count > 0)) + { + ERR_clear_error(); + break; + } + else + { + X509err(PRXYERR_F_PROXY_LOAD, PRXYERR_R_PROCESS_PROXY); + goto err; + } + } + + if (count) { + (void)sk_X509_insert(cert_chain,x,sk_X509_num(cert_chain)); + + x = NULL; + } + + count++; + + if (x) + { + X509_free(x); + x = NULL; + } + } + ret = count; + +err: + if (x != NULL) + { + X509_free(x); + } + + if (in != NULL) + { + BIO_free(in); + } + return(ret); +} + + +/********************************************************************** +Function: proxy_genreq() + +Description: + generate certificate request for a proxy certificate. + This is based on using the current user certificate. + If the current user cert is NULL, we are asking fke the server + to fill this in, and give us a new cert. Used with k5cert. + +Parameters: + +Returns: +**********************************************************************/ + +int PRIVATE +proxy_genreq( + X509 * ucert, + X509_REQ ** reqp, + EVP_PKEY ** pkeyp, + int bits, + const char * newdn, + int (*callback)()) + +{ + RSA * rsa = NULL; + EVP_PKEY * pkey = NULL; + EVP_PKEY * upkey = NULL; + X509_NAME * name = NULL; + X509_REQ * req = NULL; + X509_NAME_ENTRY * ne = NULL; + int rbits; + + if (bits) + { + rbits = bits; + } + else if (ucert) + { + if ((upkey = X509_get_pubkey(ucert)) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_PROXY_KEY); + goto err; + } + + if (upkey->type != EVP_PKEY_RSA) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_PROXY_KEY); + goto err; + } + + rbits = 8 * EVP_PKEY_size(upkey); + EVP_PKEY_free(upkey); + } + else + { + rbits = 512; + } + + if ((pkey = EVP_PKEY_new()) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_PROXY_KEY); + goto err; + } + + /* + * Note: The cast of the callback function is consistent with + * the declaration of RSA_generate_key() in OpenSSL. It may + * trigger a warning if you compile with SSLeay. + */ + if ((rsa = RSA_generate_key(rbits, + RSA_F4, + (void (*)(int,int,void *))callback + ,NULL)) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_PROXY_KEY); + goto err; + } + + if (!EVP_PKEY_assign_RSA(pkey,rsa)) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_PROXY_KEY); + goto err; + } + + if ((req = X509_REQ_new()) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_REQ); + goto err; + } + + X509_REQ_set_version(req,0L); + + if (!newdn) { + if (ucert) { + + if ((name = X509_NAME_dup(X509_get_subject_name(ucert))) == NULL) { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_REQ); + goto err; + } + } + else { + name = X509_NAME_new(); + } + + + if ((ne = X509_NAME_ENTRY_create_by_NID(NULL,NID_commonName, + V_ASN1_APP_CHOOSE, + (unsigned char *)"proxy", + -1)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_REQ); + goto err; + } + X509_NAME_add_entry(name, + ne, + X509_NAME_entry_count(name), + fix_add_entry_asn1_set_param); + } + else { + name = make_DN(newdn); + if (!name) { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_REQ); + goto err; + } + } + + X509_REQ_set_subject_name(req,name); + X509_NAME_free(name); + name = NULL; + X509_REQ_set_pubkey(req,pkey); + + if (!X509_REQ_sign(req,pkey,EVP_sha1())) + { + PRXYerr(PRXYERR_F_PROXY_GENREQ,PRXYERR_R_PROCESS_SIGN); + goto err; + } + + if (ne) + { + X509_NAME_ENTRY_free(ne); + ne = NULL; + } + + *pkeyp = pkey; + *reqp = req; + return 0; + +err: + if (upkey) + EVP_PKEY_free(upkey); + + if(rsa) + { + RSA_free(rsa); + } + if (pkey) + { + EVP_PKEY_free(pkey); + } + if (name) + { + X509_NAME_free(name); + } + if (req) + { + X509_REQ_free(req); + } + if (ne) + { + X509_NAME_ENTRY_free(ne); + } + return 1; +} + + +/** + * Sign a certificate request + * + * This function is a wrapper function for proxy_sign_ext. The subject + * name of the resulting certificate is generated by adding either + * cn=proxy or cn=limited proxy to the subject name of user_cert. The + * issuer name is set to the subject name of user_cert. + * + * @param user_cert + * A certificate to be used for subject and issuer name + * information if that information isn't provided. + * @param user_private_key + * The private key to be used for signing the certificate + * request. + * @param req + * The certificate request + * @param new_cert + * This parameter will contain the signed certficate upon + * success. + * @param seconds + * The number of seconds the new cert is going to be + * valid. The validity should not exceed that of the issuing + * key pair. If this parameter is 0 the generated cert will + * have the same lifetime as the issuing key pair. + * @param extensions + * Extensions to be placed in the new certificate. + * @param limited_proxy + * If this value is non zero the resulting cert will be a + * limited proxy. + * + * @return + * This functions returns 0 upon success, 1 upon failure. It + * will also place a more detailed error on an error stack. + */ + +int PRIVATE +proxy_sign( + X509 * user_cert, + EVP_PKEY * user_private_key, + X509_REQ * req, + X509 ** new_cert, + int seconds, + STACK_OF(X509_EXTENSION) * extensions, + int limited_proxy, + int proxyver, + const char * newdn, + const char * newissuer, + int pastproxy, + const char * newserial, + int selfsigned +) +{ + char * newcn; + EVP_PKEY * user_public_key; + X509_NAME * subject_name = NULL; + X509_NAME * issuer_name = NULL; + int rc = 0; + + unsigned char md[SHA_DIGEST_LENGTH]; + unsigned int len; + + + if(proxyver>=3) { + long sub_hash; + + user_public_key = X509_get_pubkey(user_cert); +#ifdef TYPEDEF_I2D_OF + ASN1_digest((i2d_of_void*)i2d_PUBKEY, EVP_sha1(), (char *) user_public_key, md, &len); +#else + ASN1_digest(i2d_PUBKEY, EVP_sha1(), (char *) user_public_key, md, &len); +#endif + EVP_PKEY_free(user_public_key); + + sub_hash = md[0] + (md[1] + (md[2] + (md[3] >> 1) * 256) * 256) * 256; + + newcn = snprintf_wrap("%ld", sub_hash); + } + else { + if(limited_proxy) + newcn = "limited proxy"; + else + newcn = "proxy"; + } + + if (newdn == NULL) { + if(proxy_construct_name( + user_cert, + &subject_name, + newcn, -1)) { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_PROCESS_SIGN); + if (proxyver >= 3) + free(newcn); + return 1; + } + } + else + subject_name = make_DN(newdn); + + if (newissuer) + issuer_name = make_DN(newissuer); + else + issuer_name = NULL; + + if(proxy_sign_ext(user_cert, + user_private_key, + EVP_sha1(), + req, + new_cert, + subject_name, + issuer_name, + seconds, + extensions, + proxyver, + pastproxy, + newserial, + selfsigned)) + { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_PROCESS_SIGN); + rc = 1; + } + + X509_NAME_free(subject_name); + + if (issuer_name) + X509_NAME_free(issuer_name); + + if (proxyver >= 3) + free(newcn); + + return rc; +} + +/** + * Sign a certificate request + * + * This function signs the given certificate request. Before signing + * the certificate the certificate's subject and issuer names may be + * replaced and extensions may be added to the certificate. + * + * @param user_cert + * A certificate to be used for lifetime and serial number + * information if that information isn't provided. + * @param user_private_key + * The private key to be used for signing the certificate + * request. + * @param method + * The method to employ for signing + * @param req + * The certificate request + * @param new_cert + * This parameter will contain the signed certficate upon + * success. + * @param subject_name + * The subject name to be used for the new certificate. If no + * subject name is provided the subject name in the certificate + * request will remain untouched. + * @param issuer_name + * The issuer name to be used for the new certificate. If no + * issuer name is provided the issuer name will be set to the + * subject name of the user cert. + * @param seconds + * The number of seconds the new cert is going to be + * valid. The validity should not exceed that of the issuing + * key pair. If this parameter is 0 the generated cert will + * have the same lifetime as the issuing key pair. + * @param serial_num + * The serial number to be used for the new cert. If this + * parameter is 0 the serial number of the user_cert is used. + * @param extensions + * Extensions to be placed in the new certificate. + * + * @return + * This functions returns 0 upon success, 1 upon failure. It + * will also place a more detailed error on an error stack. + */ + +int PRIVATE +proxy_sign_ext( + X509 * user_cert, + EVP_PKEY * user_private_key, + const EVP_MD * method, + X509_REQ * req, + X509 ** new_cert, + X509_NAME * subject_name, + X509_NAME * issuer_name, + int seconds, + STACK_OF(X509_EXTENSION) *extensions, + int proxyver, + int pastproxy, + const char *newserial, + int selfsigned) +{ + EVP_PKEY * new_public_key = NULL; + EVP_PKEY * tmp_public_key = NULL; + X509_CINF * new_cert_info; + X509_CINF * user_cert_info; + X509_EXTENSION * extension = NULL; + time_t time_diff, time_now, time_after; + ASN1_UTCTIME * asn1_time = NULL; + int i; + unsigned char md[SHA_DIGEST_LENGTH]; + unsigned int len; + + if (!selfsigned) + user_cert_info = user_cert->cert_info; + + *new_cert = NULL; + + if ((req->req_info == NULL) || + (req->req_info->pubkey == NULL) || + (req->req_info->pubkey->public_key == NULL) || + (req->req_info->pubkey->public_key->data == NULL)) + { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_MALFORM_REQ); + goto err; + } + + if ((new_public_key=X509_REQ_get_pubkey(req)) == NULL) { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_MALFORM_REQ); + goto err; + } + + i = X509_REQ_verify(req,new_public_key); + EVP_PKEY_free(new_public_key); + new_public_key = NULL; + + if (i < 0) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_SIG_VERIFY); + goto err; + } + + if (i == 0) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_SIG_BAD); + goto err; + } + + /* signature ok. */ + + if ((*new_cert = X509_new()) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_PROXY); + goto err; + } + + new_cert_info = (*new_cert)->cert_info; + + /* set the subject name */ + + if(subject_name && !X509_set_subject_name(*new_cert,subject_name)) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_PROXY); + goto err; + } + + /* DEE? will use same serial number, this may help + * with revocations, or may cause problems. + */ + + if (newserial) { + BIGNUM *bn = NULL; + if (BN_hex2bn(&bn, newserial) != 0) { + ASN1_INTEGER *a_int = BN_to_ASN1_INTEGER(bn, NULL); + ASN1_INTEGER_free((*new_cert)->cert_info->serialNumber); + + /* Note: The a_int == NULL case is handled below. */ + (*new_cert)->cert_info->serialNumber = a_int; + BN_free(bn); + } + } + else if (proxyver > 2) { + ASN1_INTEGER_free(X509_get_serialNumber(*new_cert)); + + new_public_key = X509_REQ_get_pubkey(req); +#ifdef TYPEDEF_I2D_OF + ASN1_digest((i2d_of_void*)i2d_PUBKEY, EVP_sha1(), (char *) new_public_key, md, &len); +#else + ASN1_digest(i2d_PUBKEY, EVP_sha1(), (char *) new_public_key, md, &len); +#endif + EVP_PKEY_free(new_public_key); + new_public_key = NULL; + + (*new_cert)->cert_info->serialNumber = ASN1_INTEGER_new(); + (*new_cert)->cert_info->serialNumber->length = len; + (*new_cert)->cert_info->serialNumber->data = malloc(len); + + if (!((*new_cert)->cert_info->serialNumber->data)) { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT, PRXYERR_R_PROCESS_PROXY); + goto err; + } + memcpy((*new_cert)->cert_info->serialNumber->data, md, SHA_DIGEST_LENGTH); + } + else if (selfsigned) { + ASN1_INTEGER *copy = ASN1_INTEGER_new(); + if (copy) { + ASN1_INTEGER_set(copy, 1); + ASN1_INTEGER_free((*new_cert)->cert_info->serialNumber); + + (*new_cert)->cert_info->serialNumber = copy; + } + else + goto err; + } + else { + ASN1_INTEGER *copy = ASN1_INTEGER_dup(X509_get_serialNumber(user_cert)); + ASN1_INTEGER_free((*new_cert)->cert_info->serialNumber); + + /* Note: The copy == NULL case is handled immediately below. */ + (*new_cert)->cert_info->serialNumber = copy; + } + + if (!(*new_cert)->cert_info->serialNumber) { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_PROXY); + goto err; + } + + + /* set the issuer name */ + + if (issuer_name) + { + if(!X509_set_issuer_name(*new_cert,issuer_name)) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_PROXY); + goto err; + } + } + else + { + if(!X509_set_issuer_name(*new_cert,X509_get_subject_name(user_cert))) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_PROXY); + goto err; + } + } + + /* Allow for a five minute clock skew here. */ + + X509_gmtime_adj(X509_get_notBefore(*new_cert),-5*60 -pastproxy); + + /* DEE? should accept an seconds parameter, and set to min of + * hours or the ucert notAfter + * for now use seconds if not zero. + */ + + if (selfsigned) { + X509_gmtime_adj(X509_get_notAfter(*new_cert),(long) seconds - pastproxy); + } + else { + /* doesn't create a proxy longer than the user cert */ + asn1_time = ASN1_UTCTIME_new(); + X509_gmtime_adj(asn1_time, -pastproxy); + time_now = ASN1_UTCTIME_mktime(asn1_time); + ASN1_UTCTIME_free(asn1_time); + time_after = ASN1_UTCTIME_mktime(X509_get_notAfter(user_cert)); + time_diff = time_after - time_now; + + if(time_diff > (seconds - pastproxy)) { + X509_gmtime_adj(X509_get_notAfter(*new_cert),(long) seconds - pastproxy); + } + else { + X509_set_notAfter(*new_cert, user_cert_info->validity->notAfter); + } + } + + /* transfer the public key from req to new cert */ + /* DEE? should this be a dup? */ + + X509_PUBKEY_free(new_cert_info->key); + new_cert_info->key = req->req_info->pubkey; + req->req_info->pubkey = NULL; + + /* + * We can now add additional extentions here + * such as to control the usage of the cert + */ + + if (new_cert_info->version == NULL) + { + if ((new_cert_info->version = ASN1_INTEGER_new()) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_PROXY); + goto err; + } + } + + ASN1_INTEGER_set(new_cert_info->version,2); /* version 3 certificate */ + + /* Free the current entries if any, there should not + * be any I belive + */ + + if (new_cert_info->extensions != NULL) + { + sk_X509_EXTENSION_pop_free(new_cert_info->extensions, + X509_EXTENSION_free); + } + + /* Add extensions provided by the client */ + + if (extensions) + { + if ((new_cert_info->extensions = + sk_X509_EXTENSION_new_null()) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_DELEGATE_COPY); + } + + /* Lets 'copy' the client extensions to the new proxy */ + /* we should look at the type, and only copy some */ + + for (i=0; iextensions, + extension)) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_DELEGATE_COPY); + goto err; + } + } + } + + /* new cert is built, now sign it */ + +#ifndef NO_DSA + /* DEE? not sure what this is doing, I think + * it is adding from the key to be used to sign to the + * new certificate any info DSA may need + */ + + tmp_public_key = X509_get_pubkey(*new_cert); + + if (EVP_PKEY_missing_parameters(tmp_public_key) && + !EVP_PKEY_missing_parameters(user_private_key)) + { + EVP_PKEY_copy_parameters(tmp_public_key,user_private_key); + } +#endif + + EVP_PKEY_free(tmp_public_key); + + if (!X509_sign(*new_cert,user_private_key,method)) + { + PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_PROCESS_SIGNC); + goto err; + } + + return 0; + +err: + /* free new_cert upon error */ + + if (*new_cert) + { + X509_free(*new_cert); + } + + if (new_public_key) + EVP_PKEY_free(new_public_key); + + return 1; +} + + + + +/** + * Construct a X509 name + * + * This function constructs a X509 name by taking the subject name of + * the certificate and adding a new CommonName field with value newcn + * (if this parameter is non NULL). The resulting name should be freed + * using X509_NAME_free. + * + * @param cert + * The certificate to extract the subject name from. + * @param name + * The resulting name + * @param newcn + * The value of the CommonName field to add. If this value is + * NULL this function just returns a copy of the subject name + * of the certificate. + * + * @return + * This functions returns 0 upon success, 1 upon failure. It + * will also place a more detailed error on an error stack. + */ + +int PRIVATE +proxy_construct_name( + X509 * cert, + X509_NAME ** name, + char * newcn, + unsigned int len) +{ + X509_NAME_ENTRY * name_entry = NULL; + *name = NULL; + + if ((*name = X509_NAME_dup(X509_get_subject_name(cert))) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_CONSTRUCT_NAME,PRXYERR_R_PROCESS_PROXY); + goto err; + } + + if(newcn) + { + if ((name_entry = X509_NAME_ENTRY_create_by_NID(NULL, + NID_commonName, + V_ASN1_APP_CHOOSE, + (unsigned char *)newcn, + len)) == NULL) + { + PRXYerr(PRXYERR_F_PROXY_CONSTRUCT_NAME,PRXYERR_R_PROCESS_PROXY); + goto err; + } + + if (!X509_NAME_add_entry(*name, + name_entry, + X509_NAME_entry_count(*name), + fix_add_entry_asn1_set_param)) + { + PRXYerr(PRXYERR_F_PROXY_CONSTRUCT_NAME,PRXYERR_R_PROCESS_PROXY); + goto err; + } + X509_NAME_ENTRY_free(name_entry); + } + + return 0; + +err: + if (*name) + { + X509_NAME_free(*name); + } + + if (name_entry) + { + X509_NAME_ENTRY_free(name_entry); + } + + return 1; + +} + + + +/********************************************************************** +Function: proxy_marshal_bp() + +Description: + Write to a bio the proxy certificate, key, users certificate, + and any other certificates need to use the proxy. + +Parameters: + +Returns: +**********************************************************************/ +int PRIVATE +proxy_marshal_bp( + BIO * bp, + X509 * ncert, + EVP_PKEY * npkey, + X509 * ucert, + STACK_OF(X509) * cert_chain) +{ + X509 * cert; + + if (!PEM_write_bio_X509(bp,ncert)) + { + return 1; + } + + if (!PEM_write_bio_RSAPrivateKey(bp, + npkey->pkey.rsa, + NULL, + NULL, + 0, + OPENSSL_PEM_CB(NULL,NULL))) + { + return 2; + } + + if (ucert) + { + if (!PEM_write_bio_X509(bp,ucert)) + { + return 3; + } + } + + if (cert_chain) + { + /* + * add additional certs, but not our cert, or the + * proxy cert, or any self signed certs + */ + int i; + + for(i=0; i < sk_X509_num(cert_chain); i++) + { + cert = sk_X509_value(cert_chain,i); + if (!(!X509_NAME_cmp_no_set(X509_get_subject_name(cert), + X509_get_subject_name(ncert)) + || (ucert && + !X509_NAME_cmp_no_set(X509_get_subject_name(cert), + X509_get_subject_name(ucert))) + || !X509_NAME_cmp_no_set(X509_get_subject_name(cert), + X509_get_issuer_name(cert)))) + { + if (!PEM_write_bio_X509(bp,cert)) + { + return 4; + } + } + } + } + + return 0; +} + +/********************************************************************** +Function: proxy_verify_init() + +Description: + +Parameters: + +Returns: +**********************************************************************/ + +void +proxy_verify_init( + proxy_verify_desc * pvd, + proxy_verify_ctx_desc * pvxd) +{ + + pvd->magicnum = PVD_MAGIC_NUMBER; /* used for debuging */ + pvd->flags = 0; + pvd->previous = NULL; + pvd->pvxd = pvxd; + pvd->proxy_depth = 0; + pvd->cert_depth = 0; + pvd->cert_chain = NULL; + pvd->limited_proxy = 0; + pvd->multiple_limited_proxy_ok = 0; +} + +/********************************************************************** +Function: proxy_verify_ctx_init() + +Description: + +Parameters: + +Returns: +**********************************************************************/ + +void +proxy_verify_ctx_init( + proxy_verify_ctx_desc * pvxd) +{ + + pvxd->magicnum = PVXD_MAGIC_NUMBER; /* used for debuging */ + pvxd->certdir = NULL; + pvxd->goodtill = 0; + +} +/********************************************************************** +Function: proxy_verify_release() + +Description: + +Parameters: + +Returns: +**********************************************************************/ + +void +proxy_verify_release( + proxy_verify_desc * pvd) +{ + pvd->cert_chain = NULL; + pvd->pvxd = NULL; +} + +/********************************************************************** +Function: proxy_verify_ctx_release() + +Description: + +Parameters: + +Returns: +**********************************************************************/ + +void +proxy_verify_ctx_release( + proxy_verify_ctx_desc * pvxd) +{ + if (pvxd->certdir) + { + free(pvxd->certdir); + pvxd->certdir = NULL; + } +} + +#if SSLEAY_VERSION_NUMBER >= 0x0090600fL +/********************************************************************** +Function: proxy_app_verify_callback() + +Description: + SSL callback which lets us do the x509_verify_cert + ourself. We use this to set the ctx->check_issued routine + so we can override some of the tests if needed. + +Parameters: + +Returns: + Same as X509_verify_cert +**********************************************************************/ + +int +proxy_app_verify_callback(X509_STORE_CTX *ctx, UNUSED(void *empty)) +{ + /* + * OpenSSL-0.9.6 has a check_issued routine which + * we want to override so we can replace some of the checks. + */ + + ctx->check_issued = proxy_check_issued; + return X509_verify_cert(ctx); +} +#endif + +/* Ifdef out all extra code not needed for k5cert + * This includes the OLDGAA + */ + +#ifndef BUILD_FOR_K5CERT_ONLY +/********************************************************************** +Function: proxy_check_proxy_name() + +Description: + Check if the subject name is a proxy, and the issuer name + is the same as the subject name, but without the proxy + entry. + i.e. inforce the proxy signing requirement of + only a user or a user's proxy can sign a proxy. + Also pass back Rif this is a limited proxy. + +Parameters: + +Returns: + -1 if there was an error + 0 if not a proxy + 1 if a proxy + 2 if a limited proxy + +*********************************************************************/ + +int proxy_check_proxy_name( + X509 * cert) +{ + int ret = 0; + X509_NAME * subject; + X509_NAME * name = NULL; + X509_NAME_ENTRY * ne = NULL; + ASN1_STRING * data; + int nidv3, nidv4 = 0; + int indexv3 = -1, indexv4 = -1; + + nidv3 = my_txt2nid(PROXYCERTINFO_V3); + nidv4 = my_txt2nid(PROXYCERTINFO_V4); + + if (nidv3 == 0 || nidv4 == 0) + ERR_clear_error(); + + indexv3 = X509_get_ext_by_NID(cert, nidv3, -1); + indexv4 = X509_get_ext_by_NID(cert, nidv4, -1); + + if (indexv3 != -1 || indexv4 != -1) { + /* Its a proxy! */ + X509_EXTENSION *ext = X509_get_ext(cert, (indexv3 == -1 ? indexv4 : indexv3)); + + if (ext) { + myPROXYCERTINFO *certinfo = NULL; + + certinfo = (myPROXYCERTINFO *)X509V3_EXT_d2i(ext); + + if (certinfo) { + myPROXYPOLICY *policy = myPROXYCERTINFO_get_proxypolicy(certinfo); + + if (policy) { +/* ASN1_OBJECT *policylang; */ +/* policylang = myPROXYPOLICY_get_policy_language(policy); */ + + /* TO DO: discover exact type of proxy. */ + + } + myPROXYCERTINFO_free(certinfo); + } +#if OPENSSL_VERSION_NUMBER >= 0x00908010 +#ifdef EXFLAG_PROXY + cert->ex_flags |= EXFLAG_PROXY; +#endif +#endif + return 1; + } + } + subject = X509_get_subject_name(cert); + ne = X509_NAME_get_entry(subject, X509_NAME_entry_count(subject)-1); + + if (!OBJ_cmp(ne->object,OBJ_nid2obj(NID_commonName))) + { + data = X509_NAME_ENTRY_get_data(ne); + if ((data->length == 5 && + !memcmp(data->data,"proxy",5)) || + (data->length == 13 && + !memcmp(data->data,"limited proxy",13))) + { + + if (data->length == 13) + { + ret = 2; /* its a limited proxy */ + } + else + { + ret = 1; /* its a proxy */ + } + /* + * Lets dup the issuer, and add the CN=proxy. This should + * match the subject. i.e. proxy can only be signed by + * the owner. We do it this way, to double check + * all the ANS1 bits as well. + */ + + /* DEE? needs some more err processing here */ + + name = X509_NAME_dup(X509_get_issuer_name(cert)); + ne = X509_NAME_ENTRY_create_by_NID(NULL, + NID_commonName, + V_ASN1_APP_CHOOSE, + (ret == 2) ? + (unsigned char *) + "limited proxy" : + (unsigned char *)"proxy", + -1); + + X509_NAME_add_entry(name,ne,X509_NAME_entry_count(name),0); + X509_NAME_ENTRY_free(ne); + ne = NULL; + + if (X509_NAME_cmp_no_set(name,subject)) + { + /* + * Reject this certificate, only the user + * may sign the proxy + */ + ret = -1; + } + X509_NAME_free(name); + } + } + +#if OPENSSL_VERSION_NUMBER >= 0x00908010 +#ifdef EXFLAG_PROXY + if (ret > 0) { + cert->ex_flags |= EXFLAG_PROXY; + if (ret == 1) + cert->ex_pcpathlen = -1; /* unlimited */ + else if (ret == 2) + cert->ex_pcpathlen = 0; /* Only at top level if limited */ + } +#endif +#endif + + return ret; +} + +#if SSLEAY_VERSION_NUMBER >= 0x0090600fL +/********************************************************************** + Function: proxy_check_issued() + +Description: + Replace the OpenSSL check_issued in x509_vfy.c with our own, + so we can override the key usage checks if its a proxy. + We are only looking for X509_V_ERR_KEYUSAGE_NO_CERTSIGN + +Parameters:r + See OpenSSL check_issued + +Returns: + See OpenSSL check_issued + +**********************************************************************/ + +int PRIVATE +proxy_check_issued( + UNUSED(X509_STORE_CTX * ctx), + X509 * x, + X509 * issuer) +{ + int ret; + int ret_code = 1; + + ret = X509_check_issued(issuer, x); + if (ret != X509_V_OK) + { + ret_code = 0; + switch (ret) + { + case X509_V_ERR_AKID_SKID_MISMATCH: + /* + * If the proxy was created with a previous version of Globus + * where the extensions where copied from the user certificate + * This error could arise, as the akid will be the wrong key + * So if its a proxy, we will ignore this error. + * We should remove this in 12/2001 + * At which time we may want to add the akid extension to the proxy. + */ + + case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: + /* + * If this is a proxy certificate then the issuer + * does not need to have the key_usage set. + * So check if its a proxy, and ignore + * the error if so. + */ + if (proxy_check_proxy_name(x) >= 1) + { + ret_code = 1; + } + break; + default: + break; + } + } + return ret_code; +} +#endif + +/********************************************************************** +Function: proxy_verify_callback() + +Description: + verify callback for SSL. Used to check that proxy + certificates are only signed by the correct user, + and used for debuging. + + Also on the server side, the s3_srvr.c code does not appear + to save the peer cert_chain, like the client side does. + We need these for additional proxies, so we need to + copy the X509 to our own stack. + +Parameters: + ok 1 then we are given one last chance to check + this certificate. + 0 then this certificate has failed, and ctx->error has the + reason. We may want to override the failure. + ctx the X509_STORE_CTX which has as a user arg, our + proxy verify desc. + +Returns: + 1 - Passed the tests + 0 - failed. The x509_vfy.c will return a failed to caller. +**********************************************************************/ + +int +proxy_verify_callback( + int ok, + X509_STORE_CTX * ctx) +{ + X509_OBJECT obj; + X509 * cert = NULL; +#ifdef X509_V_ERR_CERT_REVOKED + X509_CRL * crl; + X509_CRL_INFO * crl_info; + X509_REVOKED * revoked; +#endif + SSL * ssl = NULL; + proxy_verify_desc * pvd; + int itsaproxy = 0; + int i; + int ret; + time_t goodtill; + char * ca_policy_file_path = NULL; + char * cert_dir = NULL; + EVP_PKEY *key = NULL; + int objset = 0; + + /* + * If we are being called recursivly to check delegate + * cert chains, or being called by the grid-proxy-init, + * a pointer to a proxy_verify_desc will be + * pased in the store. If we are being called by SSL, + * by a roundabout process, the app_data of the ctx points at + * the SSL. We have saved a pointer to the context handle + * in the SSL, and its magic number should be PVD_MAGIC_NUMBER + */ + if (!(pvd = (proxy_verify_desc *) + X509_STORE_CTX_get_ex_data(ctx, + PVD_STORE_EX_DATA_IDX))) + { + ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); + if (ssl) + pvd = (proxy_verify_desc *)SSL_get_ex_data(ssl, + PVD_SSL_EX_DATA_IDX); + } + + /* + * For now we hardcode the ex_data. We could look at all + * ex_data to find ours. + * Double check that we are indeed pointing at the context + * handle. If not, we have an internal error, SSL may have changed + * how the callback and app_data are handled + */ + + if (pvd) { + if(pvd->magicnum != PVD_MAGIC_NUMBER) { + PRXYerr(PRXYERR_F_VERIFY_CB, PRXYERR_R_BAD_MAGIC); + return(0); + } + } + + /* + * We now check for some error conditions which + * can be disregarded. + */ + + if (!ok) + { + switch (ctx->error) + { +#if SSLEAY_VERSION_NUMBER >= 0x0090581fL + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + /* + * Since OpenSSL does not know about proxies, + * it will count them against the path length + * So we will ignore the errors and do our + * own checks later on, when we check the last + * certificate in the chain we will check the chain. + */ + ok = 1; + break; + +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + /* + * OpenSSL 1.0 causes the cert to be added twice to + * the store. + */ + if (proxy_check_proxy_name(ctx->cert) && + !X509_cmp(ctx->cert, ctx->current_cert)) + ok = 1; + break; +#endif + + case X509_V_ERR_INVALID_CA: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + /* + * This may happen since proxy issuers are not CAs + */ + if (proxy_check_proxy_name(ctx->cert) >= 1) { + if (proxy_check_issued(ctx, ctx->cert, ctx->current_cert)) { + ok = 1; + } + } + break; + + case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + if (proxy_check_proxy_name(ctx->cert) >= 1) { + if (check_critical_extensions(ctx->cert, 1)) + /* Allows proxy specific extensions on proxies. */ + ok = 1; + } + break; + + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_CERT_UNTRUSTED: + if (proxy_check_proxy_name(ctx->current_cert) > 0) { + /* Server side, needed to fully recognize a proxy. */ + ok = 1; + } + break; + +#ifdef X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED + case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: + /* Proxies ARE allowed */ + ok = 1; + break; +#endif + + default: + break; + } + /* if already failed, skip the rest, but add error messages */ + if (!ok) + { + if (ctx->error==X509_V_ERR_CERT_NOT_YET_VALID) + { + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CERT_NOT_YET_VALID); + ERR_set_continue_needed(); + } + else if (ctx->error==X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) + { + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_LOCAL_CA_UNKNOWN); + ERR_set_continue_needed(); + } + else if (ctx->error==X509_V_ERR_CERT_HAS_EXPIRED) + { + PRXYerr(PRXYERR_F_VERIFY_CB, PRXYERR_R_REMOTE_CRED_EXPIRED); + ERR_set_continue_needed(); + } + + goto fail_verify; + } + ctx->error = 0; + return(ok); + } + + /* Note: OpenSSL will try to verify the client's chain on the client side + before sending it abroad. However, to properly verify proxy conditions, + we need access to pvd, which is not passed. For this reason, in this + scenario we assume that if the checks above passed, everything is ok. If + it is not, it will be discovered during server-side validation of the cert. + */ + if (!pvd) + return ok; + + /* + * All of the OpenSSL tests have passed and we now get to + * look at the certificate to verify the proxy rules, + * and ca-signing-policy rules. We will also do a CRL check + */ + + /* + * Test if the name ends in CN=proxy and if the issuer + * name matches the subject without the final proxy. + */ + + ret = proxy_check_proxy_name(ctx->current_cert); + if (ret < 0) + { + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_BAD_PROXY_ISSUER); + ERR_set_continue_needed(); + ctx->error = X509_V_ERR_CERT_SIGNATURE_FAILURE; + goto fail_verify; + } + if (ret > 0) + { /* Its a proxy */ + if (ret == 2) + { + /* + * If its a limited proxy, it means it use has been limited + * during delegation. It can not sign other certs i.e. + * it must be the top cert in the chain. + * Depending on who we are, + * We may want to accept this for authentication. + * + * Globus gatekeeper -- don't accept + * sslk5d accept, but should check if from local site. + * globus user-to-user Yes, thats the purpose + * of this cert. + * + * We will set the limited_proxy flag, to show we found + * one. A Caller can then reject. + */ + + pvd->limited_proxy = 1; /* its a limited proxy */ + + if (ctx->error_depth && !pvd->multiple_limited_proxy_ok) { + /* tried to sign a cert with a limited proxy */ + /* i.e. there is still another cert on the chain */ + /* indicating we are trying to sign it! */ + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_LPROXY_MISSED_USED); + ERR_set_continue_needed(); + ctx->error = X509_V_ERR_CERT_SIGNATURE_FAILURE; + goto fail_verify; + } + } + + pvd->proxy_depth++; + itsaproxy = 1; + } + + if (!itsaproxy) + { + +#ifdef X509_V_ERR_CERT_REVOKED + int n = 0; + /* + * SSLeay 0.9.0 handles CRLs but does not check them. + * We will check the crl for this cert, if there + * is a CRL in the store. + * If we find the crl is not valid, we will fail, + * as once the sysadmin indicates that CRLs are to + * be checked, he best keep it upto date. + * + * When future versions of SSLeay support this better, + * we can remove these tests. + * we come through this code for each certificate, + * starting with the CA's We will check for a CRL + * each time, but only check the signature if the + * subject name matches, and check for revoked + * if the issuer name matches. + * this allows the CA to revoke its own cert as well. + */ + + if (X509_STORE_get_by_subject(ctx, + X509_LU_CRL, + X509_get_subject_name(ctx->current_cert), + &obj)) + { + objset = 1; + crl = obj.data.crl; + crl_info = crl->crl; + /* verify the signature on this CRL */ + + key = X509_get_pubkey(ctx->current_cert); + if (X509_CRL_verify(crl, key) <= 0) + { + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CRL_SIGNATURE_FAILURE); + ERR_set_continue_needed(); + ctx->error = X509_V_ERR_CRL_SIGNATURE_FAILURE; + goto fail_verify; + } + + /* Check date see if expired */ + + i = X509_cmp_current_time(crl_info->nextUpdate); + if (i == 0) + { + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CRL_NEXT_UPDATE_FIELD); + ERR_set_continue_needed(); + ctx->error = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD; + goto fail_verify; + } + + + if (i < 0) + { + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CRL_HAS_EXPIRED); + ERR_set_continue_needed(); + ctx->error = X509_V_ERR_CRL_HAS_EXPIRED; + goto fail_verify; + } + + /* check if this cert is revoked */ + + + n = sk_X509_REVOKED_num(crl_info->revoked); + for (i=0; irevoked,i); + + if(!ASN1_INTEGER_cmp(revoked->serialNumber, + X509_get_serialNumber(ctx->current_cert))) + { + long serial; + char buf[256]; + char *s; + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CERT_REVOKED); + serial = ASN1_INTEGER_get(revoked->serialNumber); + sprintf(buf,"%ld (0x%lX)",serial,serial); + s = X509_NAME_oneline(X509_get_subject_name( + ctx->current_cert),NULL,0); + + ERR_add_error_data(4,"Serial number = ",buf, + " Subject=",s); + + ctx->error = X509_V_ERR_CERT_REVOKED; + ERR_set_continue_needed(); + free(s); + s = NULL; + goto fail_verify; + } + } + } +#endif /* X509_V_ERR_CERT_REVOKED */ + + /* Do not need to check self signed certs against ca_policy_file */ + + if (X509_NAME_cmp(X509_get_subject_name(ctx->current_cert), + X509_get_issuer_name(ctx->current_cert))) + { + cert_dir = pvd->pvxd->certdir ? pvd->pvxd->certdir : + getenv(X509_CERT_DIR); + + { + char * error_string = NULL; + struct policy **signings = NULL; + struct policy **namespaces = NULL; + int result = SUCCESS_UNDECIDED; + + read_pathrestriction(ctx->chain, cert_dir, &namespaces, &signings); + + result = restriction_evaluate(ctx->chain, namespaces, signings); + + voms_free_policies(namespaces); + voms_free_policies(signings); + + if (result != SUCCESS_PERMIT) + { + PRXYerr(PRXYERR_F_VERIFY_CB, PRXYERR_R_CA_POLICY_VIOLATION); + + ctx->error = X509_V_ERR_INVALID_PURPOSE; + + if (error_string != NULL) + { + /* + * Seperate error message returned from policy check + * from above error message with colon + */ + + ERR_add_error_data(2, ": ", error_string); + free(error_string); + } + ERR_set_continue_needed(); + goto fail_verify; + } + else + { + if (error_string != NULL) + { + free(error_string); + } + } + } + } /* end of do not check self signed certs */ + } + + /* + * We want to determine the minimum amount of time + * any certificate in the chain is good till + * Will be used for lifetime calculations + */ + + goodtill = ASN1_UTCTIME_mktime(X509_get_notAfter(ctx->current_cert)); + if (pvd->pvxd->goodtill == 0 || goodtill < pvd->pvxd->goodtill) + { + pvd->pvxd->goodtill = goodtill; + } + + /* We need to make up a cert_chain if we are the server. + * The ssl code does not save this as I would expect. + * This is used to create a new proxy by delegation. + */ + + pvd->cert_depth++; + + if (ca_policy_file_path != NULL) + { + free(ca_policy_file_path); + } + + if (!check_critical_extensions(ctx->current_cert, itsaproxy)) { + PRXYerr(PRXYERR_F_VERIFY_CB, PRXYERR_R_UNKNOWN_CRIT_EXT); + ctx->error = X509_V_ERR_CERT_REJECTED; + goto fail_verify; + } + + /* + * We ignored any path length restrictions above because + * OpenSSL was counting proxies against the limit. + * If we are on the last cert in the chain, we + * know how many are proxies, so we can do the + * path length check now. + * See x509_vfy.c check_chain_purpose + * all we do is substract off the proxy_dpeth + */ + + if(ctx->current_cert == ctx->cert) + { + for (i=0; i < sk_X509_num(ctx->chain); i++) + { + cert = sk_X509_value(ctx->chain,i); + if (((i - pvd->proxy_depth) > 1) && (cert->ex_pathlen != -1) + && ((i - pvd->proxy_depth) > (cert->ex_pathlen + 1)) + && (cert->ex_flags & EXFLAG_BCONS)) + { + ctx->current_cert = cert; /* point at failing cert */ + ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED; + goto fail_verify; + } + } + } + + EVP_PKEY_free(key); + + if (objset) + X509_OBJECT_free_contents(&obj); + + return(ok); + +fail_verify: + + if (key) + EVP_PKEY_free(key); + + if (objset) + X509_OBJECT_free_contents(&obj); + + if (ctx->current_cert) + { + char *subject_s = NULL; + char *issuer_s = NULL; + + subject_s = X509_NAME_oneline( + X509_get_subject_name(ctx->current_cert),NULL,0); + issuer_s = X509_NAME_oneline( + X509_get_issuer_name(ctx->current_cert),NULL,0); + + switch (ctx->error) + { + case X509_V_OK: + case X509_V_ERR_INVALID_PURPOSE: + case X509_V_ERR_APPLICATION_VERIFICATION: + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CB_ERROR_MSG); + ERR_add_error_data(6, + "\n File=", + ca_policy_file_path ? ca_policy_file_path : "UNKNOWN", + "\n subject=", + subject_s ? subject_s : "UNKNOWN", + "\n issuer =", + issuer_s ? issuer_s : "UNKNOWN"); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_CERT_HAS_EXPIRED: + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CB_ERROR_MSG); + ERR_add_error_data(4, + "\n subject=", + subject_s ? subject_s : "UNKNOWN", + "\n issuer =", + issuer_s ? issuer_s : "UNKNOWN"); + break; + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CA_UNKNOWN); + ERR_add_error_data(2, "\n issuer =", + issuer_s ? issuer_s : "UNKNOWN"); + break; + + default: + PRXYerr(PRXYERR_F_VERIFY_CB,PRXYERR_R_CB_CALLED_WITH_ERROR); + ERR_add_error_data(6,"\n error =", + X509_verify_cert_error_string(ctx->error), + "\n subject=", + subject_s ? subject_s : "UNKNOWN", + "\n issuer =", + issuer_s ? issuer_s : "UNKNOWN"); + } + + free(subject_s); + free(issuer_s); + } + if (ca_policy_file_path != NULL) + { + free(ca_policy_file_path); + } + + return(0); + +} + +/********************************************************************** +Function: proxy_verify_cert_chain() + +Description: + +Parameters: + +Returns: +**********************************************************************/ + +int PRIVATE +proxy_verify_cert_chain( + X509 * ucert, + STACK_OF(X509) * cert_chain, + proxy_verify_desc * pvd) +{ + int retval = 0; + X509_STORE * cert_store = NULL; + X509_LOOKUP * lookup = NULL; + X509_STORE_CTX csc; + X509 * xcert = NULL; + X509 * scert = NULL; + int cscinitialized = 0; + + scert = ucert; + cert_store = X509_STORE_new(); + X509_STORE_set_verify_cb_func(cert_store, proxy_verify_callback); + if (cert_chain != NULL) + { + int i =0; + for (i=0;ipvxd->certdir,X509_FILETYPE_PEM); + X509_STORE_CTX_init(&csc,cert_store,scert,NULL); + cscinitialized = 1; +#if SSLEAY_VERSION_NUMBER >= 0x0090600fL + /* override the check_issued with our version */ + csc.check_issued = proxy_check_issued; +#endif + X509_STORE_CTX_set_ex_data(&csc, + PVD_STORE_EX_DATA_IDX, (void *)pvd); +#ifdef X509_V_FLAG_ALLOW_PROXY_CERTS + X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_ALLOW_PROXY_CERTS); +#endif + if(!X509_verify_cert(&csc)) + { + goto err; + } + } + retval = 1; + +err: + if (cscinitialized) + X509_STORE_CTX_cleanup(&csc); + if (cert_store) + X509_STORE_free(cert_store); + return retval; +} +#endif /* NO_PROXY_VERIFY_CALLBACK */ + + +/********************************************************************** +Function: proxy_get_filenames() + +Description: + Gets the filenames for the various files used + to store the cert, key, cert_dir and proxy. + + + Environment variables to use: + X509_CERT_DIR Directory of trusted certificates + File names are hash values, see the SSLeay + c_hash script. + X509_CERT_FILE File of trusted certifiates + X509_USER_PROXY File with a proxy certificate, key, and + additional certificates to makeup a chain + of certificates used to sign the proxy. + X509_USER_CERT User long term certificate. + X509_USER_KEY private key for the long term certificate. + + All of these are assumed to be in PEM form. If there is a + X509_USER_PROXY, it will be searched first for the cert and key. + If not defined, but a file /tmp/x509up_u is + present, it will be used, otherwise the X509_USER_CERT + and X509_USER_KEY will be used to find the certificate + and key. If X509_USER_KEY is not defined, it will be assumed + that the key is is the same file as the certificate. + + If windows, look in the registry HKEY_CURRENT_USER for the + GSI_REGISTRY_DIR, then look for the x509_user_cert, etc. + + Then try $HOME/.globus/usercert.pem + and $HOME/.globus/userkey.pem + Unless it is being run as root, then look for + /etc/grid-security/hostcert.pem and /etc/grid-security/hostkey.pem + + X509_CERT_DIR and X509_CERT_FILE can point to world readable + shared director and file. One of these must be present. + if not use $HOME/.globus/certificates + or /etc/grid-security/certificates + or $GLOBUS_DEPLOY_PATH/share/certificates + or $GLOBUS_LOCATION/share/certificates + or $GSI_DEPLOY_PATH/share/certificates + or $GSI_INSTALL_PATH/share/certificates + + The file with the key must be owned by the user, + and readable only by the user. This could be the X509_USER_PROXY, + X509_USER_CERT or the X509_USER_KEY + + X509_USER_PROXY_FILE is used to generate the default + proxy file name. + + In other words: + + proxy_get_filenames() is used by grid-proxy-init, wgpi, grid-proxy-info and + Indirectly by gss_acquire_creds. For grid-proxy-init and wgpi, the proxy_in + is 0, for acquire_creds its 1. This is used to signal how the proxy file is + to be used, 1 for input 0 for output. + + The logic for output is to use the provided input parameter, registry, + environment, or default name for the proxy. Wgpi calls this multiple times + as the options window is updated. The file will be created if needed. + + The logic for input is to use the provided input parameter, registry, + environment variable. But only use the default file if it exists, is owned + by the user, and has something in it. But not when run as root. + + Then on input if there is a proxy, the user_cert and user_key are set to + use the proxy. + + Smart card support using PKCS#11 is controled by the USE_PKCS11 flag. + + If the filename for the user key starts with SC: then it is assumed to be + of the form SC:card:label where card is the name of a smart card, and label + is the label of the key on the card. The card must be using Cryptoki + (PKCS#11) This code has been developed using the DataKey implementation + under Windows 95. + + This will allow the cert to have the same form, with the same label as well + in the future. + + + +Parameters: + +Returns: +**********************************************************************/ + +int +proxy_get_filenames( + int proxy_in, + char ** p_cert_file, + char ** p_cert_dir, + char ** p_user_proxy, + char ** p_user_cert, + char ** p_user_key) +{ + + int status = -1; + char * cert_file = NULL; + char * cert_dir = NULL; + char * user_proxy = NULL; + char * user_cert = NULL; + char * user_key = NULL; + char * home = NULL; + char * default_user_proxy = NULL; + char * default_user_cert = NULL; + char * default_user_key = NULL; + char * default_cert_dir = NULL; + char * installed_cert_dir = NULL; +#ifdef WIN32 + HKEY hkDir = NULL; + char val_user_cert[512]; + char val_user_key[512]; + char val_user_proxy[512]; + char val_cert_dir[512]; + char val_cert_file[512]; + LONG lval; + DWORD type; +#endif + +#ifdef WIN32 + RegOpenKey(HKEY_CURRENT_USER,GSI_REGISTRY_DIR,&hkDir); +#endif + + /* setup some default values */ + if (p_cert_dir) + { + cert_dir = *p_cert_dir; + } + + + if (!cert_dir) + { + cert_dir = (char *)getenv(X509_CERT_DIR); + } +#ifdef WIN32 + if (!cert_dir) + { + lval = sizeof(val_cert_dir)-1; + if (hkDir && (RegQueryValueEx(hkDir,"x509_cert_dir",0,&type, + val_cert_dir,&lval) == ERROR_SUCCESS)) + { + cert_dir = val_cert_dir; + } + } +#endif + if (p_cert_file) + { + cert_file = *p_cert_file; + } + + if (!cert_file) + { + cert_file = (char *)getenv(X509_CERT_FILE); + } +#ifdef WIN32 + if (!cert_file) + { + lval = sizeof(val_cert_file)-1; + if (hkDir && (RegQueryValueEx(hkDir,"x509_cert_file",0,&type, + val_cert_file,&lval) == ERROR_SUCCESS)) + { + cert_file = val_cert_file; + } + } +#endif + + if (cert_dir == NULL) + { + + /* + * If ~/.globus/certificates exists, then use that + */ + home = getenv("HOME"); +#ifndef WIN32 + /* Under windows use c:\windows as default home */ + if (!home) + { + home = "c:\\windows"; + } +#endif /* WIN32 */ + + if (home) + { + default_cert_dir = snprintf_wrap("%s%s%s", + home, FILE_SEPERATOR, X509_DEFAULT_CERT_DIR); + + if (!default_cert_dir) + { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + if (checkstat(default_cert_dir) != 1) + { + /* default_cert_dir exists */ + cert_dir = default_cert_dir; + } + } + + + /* + * Now check for host based default directory + */ + if (!cert_dir) + { + + if (checkstat(X509_INSTALLED_HOST_CERT_DIR) != 1) + { + /* default_cert_dir exists */ + cert_dir = X509_INSTALLED_HOST_CERT_DIR; + } + } + + if (!cert_dir) + { + /* + * ...else look for (in order) + * $GLOBUS_DEPLOY_PATH/share/certificates + * $GLOBUS_LOCATION/share/certficates + */ + char *globus_location; + + + globus_location = getenv("GLOBUS_DEPLOY_PATH"); + + if (!globus_location) + { + globus_location = getenv("GLOBUS_LOCATION"); + } + + if (!globus_location) + { + globus_location = getenv("GSI_DEPLOY_PATH"); + } + + if (!globus_location) + { + globus_location = getenv("GSI_INSTALL_PATH"); + } + + if (globus_location) + { + installed_cert_dir = snprintf_wrap("%s%s%s", + globus_location, + FILE_SEPERATOR, + X509_INSTALLED_CERT_DIR); + + if (!installed_cert_dir) + { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + /* + * Previous code always set cert_dir to + * default_cert_dir without checking for its + * existance, so we'll also skip the existance + * check here. + */ + cert_dir = installed_cert_dir; + } + } + + if (!cert_dir) + { + cert_dir = X509_INSTALLED_HOST_CERT_DIR; + } + } + + if (cert_dir) + { + if (checkstat(cert_dir) == 1) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERTS); + ERR_add_error_data(2,"x509_cert_dir=",cert_dir); + goto err; + } + } + + if (cert_file) + { + if (checkstat(cert_file) == 1) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERTS); + ERR_add_error_data(2,"x509_cert_file=",cert_file); + goto err; + } + } + /* if X509_USER_PROXY is defined, use it for cert and key, + * and for additional certs. + * if not, and the default user_proxy file is present, + * use it. + * If not, get the X509_USER_CERT and X509_USER_KEY + * if not, use ~/.globus/usercert.pem ~/.globus/userkey.pem + */ + if (p_user_proxy) + { + user_proxy = *p_user_proxy; + } + + if (!user_proxy) + { + user_proxy = (char *)getenv(X509_USER_PROXY); + } +#ifdef WIN32 + if (!user_proxy) + { + lval = sizeof(val_user_proxy)-1; + if (hkDir && (RegQueryValueEx(hkDir,"x509_user_proxy",0,&type, + val_user_proxy,&lval) == ERROR_SUCCESS)) + { + user_proxy = val_user_proxy; + } + } +#endif + if (!user_proxy && !getenv("X509_RUN_AS_SERVER")) + { + default_user_proxy = snprintf_wrap("%s%s%s%lu", + DEFAULT_SECURE_TMP_DIR, + FILE_SEPERATOR, + X509_USER_PROXY_FILE, + getuid()); + + if (!default_user_proxy) + { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + +#ifndef WIN32 + if ((!proxy_in || getuid() != 0) + && checkstat(default_user_proxy) == 0) +#endif + { + user_proxy = default_user_proxy; + } + } + if (proxy_in && user_proxy) + { + user_cert = user_proxy; + user_key = user_proxy; + } + else + { + if (!user_proxy && !proxy_in) + { + user_proxy = default_user_proxy; + } + + if (p_user_cert) + { + user_cert = *p_user_cert; + } + + if(!user_cert) + { + user_cert = (char *)getenv(X509_USER_CERT); + } + +#ifdef WIN32 + if (!user_cert) + { + lval = sizeof(val_user_cert)-1; + if (hkDir && (RegQueryValueEx( + hkDir, + "x509_user_cert", + 0, + &type, + val_user_cert,&lval) == ERROR_SUCCESS)) + { + user_cert = val_user_cert; + } + } +#endif + if (user_cert) + { + if (p_user_key) + { + user_key = *p_user_key; + } + if (!user_key) + { + user_key = (char *)getenv(X509_USER_KEY); + } +#ifdef WIN32 + if (!user_key) + { + lval = sizeof(val_user_key)-1; + if (hkDir && (RegQueryValueEx( + hkDir, + "x509_user_key", + 0, + &type, + val_user_key,&lval) == ERROR_SUCCESS)) + { + user_key = val_user_key; + } + } +#endif + if (!user_key) + { + user_key = user_cert; + } + } + else + { +#ifndef WIN32 + if (getuid() == 0) + { + if (checkstat(X509_DEFAULT_HOST_CERT) != 1) + { + user_cert = X509_DEFAULT_HOST_CERT; + } + if (checkstat(X509_DEFAULT_HOST_KEY) != 1) + { + user_key = X509_DEFAULT_HOST_KEY; + } + } + else +#endif + { + if (!home) + { + home = getenv("HOME"); + } + if (!home) + { +#ifndef WIN32 + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_NO_HOME); + goto err; +#else + home = "c:\\"; +#endif + } + + default_user_cert = snprintf_wrap("%s%s%s", + home, FILE_SEPERATOR, X509_DEFAULT_USER_CERT); + + if (!default_user_cert) + { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + default_user_key = snprintf_wrap("%s%s%s", + home,FILE_SEPERATOR, X509_DEFAULT_USER_KEY); + + if (!default_user_key) + { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + user_cert = default_user_cert; + user_key = default_user_key; + + /* Support for pkcs12 credentials. */ + { + int fd = open(default_user_cert, O_RDONLY); + if (fd >= 0) + close(fd); + else { + /* Cannot open normal file -- look for pkcs12. */ + char *certname = NULL; + + free(default_user_cert); + free(default_user_key); + + + certname = getenv("X509_USER_CRED"); + + if (!certname) { + default_user_cert = snprintf_wrap("%s%s%s", + home, FILE_SEPERATOR, X509_DEFAULT_USER_CERT_P12); + + if (!default_user_cert) { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + if (checkstat(default_user_cert) != 0) { + free(default_user_cert); + default_user_cert = snprintf_wrap("%s%s%s", + home, FILE_SEPERATOR, X509_DEFAULT_USER_CERT_P12_GT); + } + + if (!default_user_cert) { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + } + else + strcpy(default_user_cert, certname); + + default_user_key = strndup(default_user_cert, strlen(default_user_cert)); + + if (!default_user_key) { + PRXYerr(PRXYERR_F_INIT_CRED, PRXYERR_R_OUT_OF_MEMORY); + goto err; + } + + user_cert = default_user_cert; + user_key = default_user_key; + } + } + } + } + } + + status = 0; +err: + if (!status) { + if (p_cert_file && cert_file && !(*p_cert_file)) { + *p_cert_file = strdup(cert_file); + } + if (p_cert_dir && cert_dir && !(*p_cert_dir)) { + *p_cert_dir = strdup(cert_dir); + } + if (p_user_proxy && user_proxy && !(*p_user_proxy)) { + *p_user_proxy = strdup(user_proxy); + } + if (p_user_cert && user_cert && !(*p_user_cert)) { + free(*p_user_cert); + *p_user_cert = strdup(user_cert); + } + if (p_user_key && user_key && !(*p_user_key)) { + free(*p_user_key); + *p_user_key = strdup(user_key); + } + } +#ifdef WIN32 + if (hkDir) + { + RegCloseKey(hkDir); + } +#endif + + free(default_user_proxy); + free(installed_cert_dir); + free(default_cert_dir); + free(default_user_cert); + free(default_user_key); + + return status; +} +/********************************************************************** +Function: proxy_load_user_cert() + +Description: + loads the users cert. May need a pw callback for Smartcard PIN. + May use a smartcard too. + +Parameters: + +Returns: +**********************************************************************/ + +static int cert_load_pkcs12(BIO *bio, int (*pw_cb)(), X509 **cert, EVP_PKEY **key, STACK_OF(X509) **chain) +{ + PKCS12 *p12 = NULL; + char *password = NULL; + char buffer[1024]; + int ret = 0; + + p12 = d2i_PKCS12_bio(bio, NULL); + if (!p12) + return 0; + + if (!PKCS12_verify_mac(p12, "", 0)) { + + int sz = 0; + + if (pw_cb) + sz = pw_cb(buffer, 1024, 0); + else + if (EVP_read_pw_string(buffer, 1024, EVP_get_pw_prompt(), 0) != -1) + sz = strlen(buffer); + + if (sz) + password = buffer; + else + goto err; + } + else + password=""; + + ret = PKCS12_parse(p12, password, key, cert, chain); + + err: + memset(buffer, 0, 1024); + + if (p12) + PKCS12_free(p12); + + return ret; +} + +int PRIVATE proxy_load_user_cert_and_key_pkcs12(const char *user_cert, + X509 **cert, + STACK_OF(X509) **stack, + EVP_PKEY **pkey, + int (*pw_cb) ()) +{ + BIO *bio = BIO_new_file(user_cert, "rb"); + int res = cert_load_pkcs12(bio, pw_cb, cert, pkey, stack); + BIO_free(bio); + + if (res) + return 1; + else { + if (ERR_peek_error() == ERR_PACK(ERR_LIB_PEM,PEM_F_PEM_READ_BIO,PEM_R_NO_START_LINE)) { + ERR_clear_error(); + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_INVALID_CERT); + } + else { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERT); + } + ERR_add_error_data(2, "\n File=", user_cert); + return 0; + } +} + + + +int PRIVATE +proxy_load_user_cert( + const char * user_cert, + X509 ** certificate, + UNUSED(int (*pw_cb)()), + UNUSED(unsigned long * hSession)) +{ + int status = -1; + FILE * fp; + + /* Check arguments */ + if (!user_cert) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_USER_NOCERT_FILE); + status = PRXYERR_R_PROBLEM_USER_NOCERT_FILE; + + ERR_add_error_data(1, "\n No certificate file found"); + goto err; + } + + if (!strncmp(user_cert,"SC:",3)) + { +#ifdef USE_PKCS11 + char * cp; + char * kp; + int rc; + + cp = user_cert + 3; + kp = strchr(cp,':'); + if (kp == NULL) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_USER_NOCERT_FILE); + ERR_add_error_data(2, "\n SmartCard reference=", + user_cert); + status = PRXYERR_R_PROBLEM_USER_NOCERT_FILE; + goto err; + } + + kp++; /* skip the : */ + + if (*hSession == 0) + { + rc = sc_init(hSession, cp, NULL, NULL, CKU_USER, 0); + + if (rc) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERT); + ERR_add_error_data( + 1, + "\n Failed to open session to smartcard"); + status = PRXYERR_R_PROCESS_CERT; + goto err; + } + } + rc = sc_get_cert_obj_by_label(*hSession,kp, + certificate); + if (rc) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERT); + ERR_add_error_data( + 2, + "\n Could not find certificate on smartcard, label=", + kp); + status = PRXYERR_R_PROCESS_CERT; + goto err; + } +#else + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERT); + ERR_add_error_data( + 1, + "\n Smartcard support not compiled with this program"); + status = PRXYERR_R_PROCESS_CERT; + goto err; + + /* + * DEE? need to add a random number routine here, to use + * the random number generator on the card + */ + +#endif /* USE_PKCS11 */ + } + else + { + if((fp = fopen(user_cert,"rb")) == NULL) { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_USER_NOCERT_FILE); + status = PRXYERR_R_PROBLEM_USER_NOCERT_FILE; + + ERR_add_error_data(2, "\n Cert File=", user_cert); + goto err; + } + + if (PEM_read_X509(fp, + certificate, + OPENSSL_PEM_CB(NULL,NULL)) == NULL) { + if (ERR_peek_error() == ERR_PACK(ERR_LIB_PEM,PEM_F_PEM_READ_BIO,PEM_R_NO_START_LINE)) { + ERR_clear_error(); + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_INVALID_CERT); + status = PRXYERR_R_INVALID_CERT; + } + else { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_CERT); + status = PRXYERR_R_PROCESS_CERT; + } + + ERR_add_error_data(2, "\n File=", user_cert); + fclose(fp); + goto err; + } + fclose(fp); + } + status = 0; + err: + + return status; +} + + +/********************************************************************** +Function: proxy_load_user_key() + +Description: + loads the users key. Assumes the cert has been loaded, + and checks they match. + May use a smartcard too. + +Parameters: + +Returns: + an int specifying the error +**********************************************************************/ + +int PRIVATE +proxy_load_user_key( + EVP_PKEY ** private_key, + X509 * ucert, + const char * user_key, + int (*pw_cb)(), + UNUSED(unsigned long * hSession)) +{ + int status = -1; + FILE * fp; + EVP_PKEY * ucertpkey; + int (*xpw_cb)(); + + if (!private_key) + return 0; + + xpw_cb = pw_cb; +#ifdef WIN32 + if (!xpw_cb) + { + xpw_cb = read_passphrase_win32; + } +#endif + + /* Check arguments */ + if (!user_key) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_USER_NOKEY_FILE); + status = PRXYERR_R_PROBLEM_USER_NOKEY_FILE; + + ERR_add_error_data(1,"\n No key file found"); + goto err; + } + + + if (!strncmp(user_key,"SC:",3)) + { +#ifdef USE_PKCS11 + char *cp; + char *kp; + int rc; + + cp = user_key + 3; + kp = strchr(cp,':'); + if (kp == NULL) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_KEY_FILE); + ERR_add_error_data(2,"\n SmartCard reference=",user_key); + status = PRXYERR_R_PROBLEM_KEY_FILE; + goto err; + } + kp++; /* skip the : */ + if (*hSession == 0) + { + rc = sc_init(hSession, cp, NULL, NULL, CKU_USER, 0); + if (rc) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_KEY); + ERR_add_error_data( + 1, + "\n Failed to open session to smartcard"); + status = PRXYERR_R_PROCESS_KEY; + goto err; + } + } + rc = sc_get_priv_key_obj_by_label(hSession,kp, + private_key); + if (rc) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_KEY); + ERR_add_error_data( + 2, + "\n Could not find key on smartcard, label=", + kp); + status = PRXYERR_R_PROCESS_KEY; + goto err; + } +#else + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_KEY); + ERR_add_error_data( + 1, + "\n Smartcard support not compiled with this program"); + status = PRXYERR_R_PROCESS_KEY; + goto err; + + /* + * DEE? could add a random number routine here, to use + * the random number generator on the card + */ + +#endif /* USE_PKCS11 */ + } + else + { + int keystatus; + + if ((fp = fopen(user_key,"rb")) == NULL) { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_USER_NOKEY_FILE); + status = PRXYERR_R_PROBLEM_USER_NOKEY_FILE; + + ERR_add_error_data(2, "\n File=",user_key); + goto err; + } + + /* user key must be owned by the user, and readable + * only be the user + */ + + if ((keystatus = checkstat(user_key))) { + if (keystatus == 4) { + status = PRXYERR_R_USER_ZERO_LENGTH_KEY_FILE; + PRXYerr(PRXYERR_F_INIT_CRED, + PRXYERR_R_USER_ZERO_LENGTH_KEY_FILE); + } + else { + status = PRXYERR_R_PROBLEM_KEY_FILE; + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROBLEM_KEY_FILE); + } + + ERR_add_error_data(2, "\n File=", user_key); + fclose(fp); + goto err; + } + + if (PEM_read_PrivateKey(fp, + private_key, + OPENSSL_PEM_CB(xpw_cb,NULL)) == NULL) { + unsigned long error = ERR_peek_error(); + fclose(fp); + +#ifdef PEM_F_PEM_DEF_CALLBACK + if (error == ERR_PACK(ERR_LIB_PEM, + PEM_F_PEM_DEF_CALLBACK, + PEM_R_PROBLEMS_GETTING_PASSWORD)) +#else + if (error == ERR_PACK(ERR_LIB_PEM, + PEM_F_DEF_CALLBACK, + PEM_R_PROBLEMS_GETTING_PASSWORD)) +#endif + { + ERR_clear_error(); + } +#ifdef EVP_F_EVP_DECRYPTFINAL_EX + else if (error == ERR_PACK(ERR_LIB_EVP, + EVP_F_EVP_DECRYPTFINAL_EX, + EVP_R_BAD_DECRYPT)) +#else + else if (error == ERR_PACK(ERR_LIB_EVP, + EVP_F_EVP_DECRYPTFINAL, + EVP_R_BAD_DECRYPT)) +#endif + { + ERR_clear_error(); + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_WRONG_PASSPHRASE); + status = PRXYERR_R_WRONG_PASSPHRASE; + } + else { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_PROCESS_KEY); + ERR_add_error_data(2, "\n File=", user_key); + status = PRXYERR_R_PROCESS_KEY; + } + goto err; + } + fclose(fp); + } + + /* + * check that the private key matches the certificate + * Dont want a mixup of keys and certs + * Will only check rsa type for now. + */ + if (ucert) + { + X509_PUBKEY *key = X509_get_X509_PUBKEY(ucert); + ucertpkey = X509_PUBKEY_get(key); + int mismatch = 0; + + if (ucertpkey!= NULL && ucertpkey->type == + (*private_key)->type) + { + if (ucertpkey->type == EVP_PKEY_RSA) + { + /* add in key as random data too */ + if (ucertpkey->pkey.rsa != NULL) + { + if(ucertpkey->pkey.rsa->p != NULL) + { + RAND_add((void*)ucertpkey->pkey.rsa->p->d, + BN_num_bytes(ucertpkey->pkey.rsa->p), + BN_num_bytes(ucertpkey->pkey.rsa->p)); + } + if(ucertpkey->pkey.rsa->q != NULL) + { + RAND_add((void*)ucertpkey->pkey.rsa->q->d, + BN_num_bytes(ucertpkey->pkey.rsa->q), + BN_num_bytes(ucertpkey->pkey.rsa->q)); + } + } + if ((ucertpkey->pkey.rsa != NULL) && + (ucertpkey->pkey.rsa->n != NULL) && + ((*private_key)->pkey.rsa != NULL) ) + { + if ((*private_key)->pkey.rsa->n != NULL + && BN_num_bytes((*private_key)->pkey.rsa->n)) + { + if (BN_cmp(ucertpkey->pkey.rsa->n, + (*private_key)->pkey.rsa->n)) + { + mismatch=1; + } + } + else + { + (*private_key)->pkey.rsa->n = + BN_dup(ucertpkey->pkey.rsa->n); + (*private_key)->pkey.rsa->e = + BN_dup(ucertpkey->pkey.rsa->e); + } + } + } + } + else + { + mismatch=1; + } + + EVP_PKEY_free(ucertpkey); + + if (mismatch) + { + PRXYerr(PRXYERR_F_INIT_CRED,PRXYERR_R_KEY_CERT_MISMATCH); + status = PRXYERR_R_KEY_CERT_MISMATCH; + goto err; + } + } + + status = 0; + +err: + /* DEE need more cleanup */ + return status; +} + + +/********************************************************************** +Function: ASN1_UTCTIME_mktime() + +Description: + SSLeay only has compare functions to the current + So we define a convert to time_t from which we can do differences + Much of this it taken from the X509_cmp_current_time() + routine. + +Parameters: + +Returns: + time_t +**********************************************************************/ + +time_t PRIVATE ASN1_TIME_mktime(ASN1_TIME *ctm) +{ + /* + * note: ASN1_TIME, ASN1_UTCTIME, ASN1_GENERALIZEDTIME are different + * typedefs of the same type. + */ + return ASN1_UTCTIME_mktime(ctm); +} + +time_t PRIVATE +ASN1_UTCTIME_mktime( + ASN1_UTCTIME * ctm) +{ + char *str; + time_t offset; + time_t newtime; + char buff1[32]; + char *p; + int i; + struct tm tm; + int size = 0; + + switch (ctm->type) { + case V_ASN1_UTCTIME: + size=10; + break; + case V_ASN1_GENERALIZEDTIME: + size=12; + break; + } + p = buff1; + i = ctm->length; + str = (char *)ctm->data; + if ((i < 11) || (i > 17)) { + return 0; + } + memcpy(p,str,size); + p += size; + str += size; + + if ((*str == 'Z') || (*str == '-') || (*str == '+')) { + *(p++)='0'; *(p++)='0'; + } + else { + *(p++)= *(str++); *(p++)= *(str++); + } + *(p++) = 'Z'; + *p = '\0'; + + if (*str == 'Z') { + offset=0; + } + else { + if ((*str != '+') && (str[5] != '-')) { + return 0; + } + offset=((str[1]-'0')*10+(str[2]-'0'))*60; + offset+=(str[3]-'0')*10+(str[4]-'0'); + if (*str == '-') { + offset=-offset; + } + } + + tm.tm_isdst = 0; + int index = 0; + if (ctm->type == V_ASN1_UTCTIME) { + tm.tm_year = (buff1[index++]-'0')*10; + tm.tm_year += (buff1[index++]-'0'); + } + else { + tm.tm_year = (buff1[index++]-'0')*1000; + tm.tm_year += (buff1[index++]-'0')*100; + tm.tm_year += (buff1[index++]-'0')*10; + tm.tm_year += (buff1[index++]-'0'); + } + + if (tm.tm_year < 70) { + tm.tm_year+=100; + } + + if (tm.tm_year > 1900) { + tm.tm_year -= 1900; + } + + tm.tm_mon = (buff1[index++]-'0')*10; + tm.tm_mon += (buff1[index++]-'0')-1; + tm.tm_mday = (buff1[index++]-'0')*10; + tm.tm_mday += (buff1[index++]-'0'); + tm.tm_hour = (buff1[index++]-'0')*10; + tm.tm_hour += (buff1[index++]-'0'); + tm.tm_min = (buff1[index++]-'0')*10; + tm.tm_min += (buff1[index++]-'0'); + tm.tm_sec = (buff1[index++]-'0')*10; + tm.tm_sec += (buff1[index]-'0'); + + /* + * mktime assumes local time, so subtract off + * timezone, which is seconds off of GMT. first + * we need to initialize it with tzset() however. + */ + + tzset(); +#if defined(HAVE_TIMEGM) + newtime = (timegm(&tm) + offset*60*60); +#elif defined(HAVE_TIME_T_TIMEZONE) + newtime = (mktime(&tm) + offset*60*60 - timezone); +#elif defined(HAVE_TIME_T__TIMEZONE) + newtime = (mktime(&tm) + offset*60*60 - _timezone); +#else + newtime = (mktime(&tm) + offset*60*60); +#endif + + return newtime; +} + + +#ifdef CLASS_ADD + +/********************************************************************** +Function: proxy_extension_class_add_create() + +Description: + create a X509_EXTENSION for the class_add info. + +Parameters: + A buffer and length. The date is added as + ANS1_OCTET_STRING to an extension with the + class_add OID. + +Returns: + +**********************************************************************/ + +X509_EXTENSION PRIVATE * +proxy_extension_class_add_create( + void * buffer, + size_t length) + +{ + X509_EXTENSION * ex = NULL; + ASN1_OBJECT * class_add_obj = NULL; + ASN1_OCTET_STRING * class_add_oct = NULL; + int crit = 0; + + if(!(class_add_obj = OBJ_nid2obj(OBJ_txt2nid("CLASSADD")))) + { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_OID); + goto err; + } + + if(!(class_add_oct = ASN1_OCTET_STRING_new())) + { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + + class_add_oct->data = buffer; + class_add_oct->length = length; + + if (!(ex = X509_EXTENSION_create_by_OBJ(NULL, class_add_obj, + crit, class_add_oct))) + { + PRXYerr(PRXYERR_F_PROXY_SIGN,PRXYERR_R_CLASS_ADD_EXT); + goto err; + } + class_add_oct = NULL; + + return ex; + +err: + if (class_add_oct) + { + ASN1_OCTET_STRING_free(class_add_oct); + } + + if (class_add_obj) + { + ASN1_OBJECT_free(class_add_obj); + } + return NULL; +} +#endif + + +int PRIVATE determine_filenames(char **cacert, char **certdir, char **outfile, + char **certfile, char **keyfile, int noregen) +{ + char *oldoutfile = NULL; + + if (noregen) { + int modify = 0; + + if (*certfile == NULL && *keyfile == NULL) + modify = 1; + + if (proxy_get_filenames(0, NULL, NULL, &oldoutfile, certfile, keyfile)) + goto err; + + if (modify) { + free(*certfile); + free(*keyfile); + *certfile = strdup(oldoutfile); + *keyfile = oldoutfile; + } + else + free(oldoutfile); + + if (proxy_get_filenames(0, cacert, certdir, outfile, certfile, keyfile)) + goto err; + } + else if (proxy_get_filenames(0, cacert, certdir, outfile, certfile, keyfile)) + goto err; + + return 1; + +err: + return 0; +} + +int load_credentials(const char *certname, const char *keyname, + X509 **cert, STACK_OF(X509) **stack, EVP_PKEY **key, + int (*callback)()) +{ + STACK_OF(X509) *chain = NULL; + + if (!certname) + return 0; + + unsigned long hSession = 0; + + if (!strncmp(certname, "SC:", 3)) + EVP_set_pw_prompt("Enter card pin:"); + else + EVP_set_pw_prompt("Enter GRID pass phrase for this identity:"); + + if (strcmp(certname + strlen(certname) - 4, ".p12")) { + if(proxy_load_user_cert(certname, cert, callback, &hSession)) + goto err; + + EVP_set_pw_prompt("Enter GRID pass phrase:"); + + if (keyname) { + if (!strncmp(keyname, "SC:", 3)) + EVP_set_pw_prompt("Enter card pin:"); + + if (proxy_load_user_key(key, *cert, keyname, callback, &hSession)) + goto err; + } + + if (stack && (strncmp(certname, "SC:", 3) && (!keyname || !strcmp(certname, keyname)))) { + chain = sk_X509_new_null(); + if (proxy_load_user_proxy(chain, certname) < 0) + goto err; + *stack = chain; + } + } + else { + if (!proxy_load_user_cert_and_key_pkcs12(certname, cert, stack, key, callback)) + goto err; + } + + return 1; + +err: + if (chain) + sk_X509_free(chain); + if (cert) { + X509_free(*cert); + *cert = NULL; + } + if (key) { + EVP_PKEY_free(*key); + *key = NULL; + } + return 0; +} + +int PRIVATE load_certificate_from_file(FILE *file, X509 **cert, + STACK_OF(X509) **stack) +{ + BIO *in = NULL; + + if (!cert) + return 0; + + in = BIO_new_fp(file, BIO_NOCLOSE); + + if (in) { + *cert = PEM_read_bio_X509(in, NULL, 0, NULL); + + if(!*cert) + goto err; + + if (stack) { + *stack = load_chain(in, 0); + if (!(*stack)) + goto err; + } + } + BIO_free(in); + return 1; + + err: + BIO_free(in); + if (cert) + X509_free(*cert); + if (stack) + sk_X509_pop_free(*stack, X509_free); + return 0; + +} + +STACK_OF(X509) *load_chain(BIO *in, char *certfile) +{ + STACK_OF(X509_INFO) *sk=NULL; + STACK_OF(X509) *stack=NULL, *ret=NULL; + X509_INFO *xi; + int first = 1; + + if(!(stack = sk_X509_new_null())) { + if (certfile) + printf("memory allocation failure\n"); + goto end; + } + + /* This loads from a file, a stack of x509/crl/pkey sets */ + if(!(sk=PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) { + if (certfile) + printf("error reading the file, %s\n",certfile); + goto end; + } + + /* scan over it and pull out the certs */ + while (sk_X509_INFO_num(sk)) { + /* skip first cert */ + if (first) { + first = 0; + continue; + } + xi=sk_X509_INFO_shift(sk); + if (xi->x509 != NULL) { + sk_X509_push(stack,xi->x509); + xi->x509=NULL; + } + X509_INFO_free(xi); + } + if(!sk_X509_num(stack)) { + if (certfile) + printf("no certificates in file, %s\n",certfile); + sk_X509_free(stack); + goto end; + } + ret=stack; +end: + sk_X509_INFO_free(sk); + return(ret); +} + +static char hextoint(char r, char s) +{ + int v = 0; + if (isxdigit(r) && isxdigit(s)) { + v = hex2num(r); + v <<= 4; + v += hex2num(s); + } + return v; +} + +static unsigned char *reencode_string(unsigned char *string, int *len) +{ + unsigned char *temp = string; + unsigned char *pos = string; + char t = '\0'; + char r = '\0'; + *len = 0; + + while(*string) { + switch (*string) { + case '\\': + t = *++string; + + if (t == '\\') { + *pos++ = '\\'; + ++(*len); + } + else if (isxdigit(t)) { + r = *++string; + *pos++ = hextoint(tolower(t), tolower(r)); + ++(*len); + ++string; + } + else { + *pos++ = t; + ++(*len); + ++string; + } + break; + + default: + ++(*len); + *pos++ = *string++; + break; + } + } + + return temp; +} + +static X509_NAME *make_DN(const char *dnstring) +{ + char *buffername = (char*)malloc(strlen(dnstring)+1); + unsigned char *buffervalue = (unsigned char*)malloc(strlen(dnstring)+1); + char *currentname; + unsigned char *currentvalue; + X509_NAME *name = NULL; + int valuelen = 0; + char next = 0; + + name = X509_NAME_new(); + + int status = 0; /* + * 0 = looking for /type + * 1 = looking for value + */ + do { + switch (status) { + case 0: + /* Parse for /Name= */ + currentname=buffername; + while (*dnstring) { + if (*dnstring == '\\') { + *currentname++ = *++dnstring; + if (*dnstring == '\0') { + break; + } + dnstring++; + } + else if (*dnstring == '=') { + *currentname='\0'; + break; + } + else if (*dnstring == '\0') { + break; + } + else + *currentname++ = *dnstring++; + } + /* now, if *dnstring == '\0' then error; */ + + if (*dnstring == '\0') + goto err; + /* else, we got a type, now look for a value. */ + status = 1; + dnstring++; + break; + case 1: + /* Parse for value */ + currentvalue=buffervalue; + while (*dnstring) { + if (*dnstring == '\\') { + next = *++dnstring; + if (next == '\0') { + break; + } + else if (next != '/') { + *currentvalue++ = '\\'; + *currentvalue++ = next; + } + else { + *currentvalue++ = '/'; + } + dnstring++; + } + else if (*dnstring == '/') { + *currentvalue='\0'; + break; + } + else if (*dnstring == '\0') { + *currentvalue='\0'; + break; + } + else + *currentvalue++ = *dnstring++; + } + + *currentvalue='\0'; + if (strlen((char*)buffervalue) == 0) + goto err; + + /* Now we have both type and value. Add to the X509_NAME_ENTRY */ + + buffervalue = reencode_string(buffervalue, &valuelen); + + X509_NAME_add_entry_by_txt(name, buffername+1, /* skip initial '/' */ + V_ASN1_APP_CHOOSE, + buffervalue, valuelen, X509_NAME_entry_count(name), + 0); + status = 0; + break; + } + } while (*dnstring); + + free(buffername); + free(buffervalue); + + return name; + err: + free(buffername); + free(buffervalue); + X509_NAME_free(name); + + return NULL; + +} + +static int check_critical_extensions(X509 *cert, int itsaproxy) +{ + int i = 0; + ASN1_OBJECT *extension_obj; + int nid; + X509_EXTENSION *ex; + + int nid_pci3 = my_txt2nid(PROXYCERTINFO_V3); + int nid_pci4 = my_txt2nid(PROXYCERTINFO_V4); + + STACK_OF(X509_EXTENSION) *extensions = cert->cert_info->extensions; + + for (i=0; i < sk_X509_EXTENSION_num(extensions); i++) { + ex = (X509_EXTENSION *) sk_X509_EXTENSION_value(extensions,i); + + if(X509_EXTENSION_get_critical(ex)) { + extension_obj = X509_EXTENSION_get_object(ex); + + nid = OBJ_obj2nid(extension_obj); + + if (itsaproxy) { + if (nid != NID_basic_constraints && + nid != NID_key_usage && + nid != NID_ext_key_usage && + nid != NID_netscape_cert_type && + nid != NID_subject_key_identifier && + nid != NID_authority_key_identifier && + nid != nid_pci3 && + nid != nid_pci4) { + return 0; + } + } + else { + if (nid != NID_basic_constraints && + nid != NID_key_usage && + nid != NID_ext_key_usage && + nid != NID_netscape_cert_type && + nid != NID_subject_key_identifier && + nid != NID_authority_key_identifier) { + return 0; + } + } + } + } + return 1; +} diff --git a/emi.canl.canl-c/src/proxy/sslutils.h b/emi.canl.canl-c/src/proxy/sslutils.h new file mode 100644 index 0000000..adeff08 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/sslutils.h @@ -0,0 +1,533 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * Valerio Venturi - Valerio.Venturi@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ +/********************************************************************** +sslutils.h: + +Description: + This header file used internally by the gssapi_ssleay + routines + +**********************************************************************/ + +#ifndef VOMS_SSLUTILS_H +#define VOMS_SSLUTILS_H + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +/********************************************************************** + Include header files +**********************************************************************/ +//#include "config.h" + +#include +#include +#include +#include "openssl/crypto.h" + + + +#if defined(__GNUC__) +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +#define UNUSED(z) z __attribute__ ((unused)) +#else +#define UNUSED(z) z +#endif +#define PRIVATE __attribute__ ((visibility ("hidden"))) +#define PUBLIC __attribute__ ((visibility ("default"))) +#else +#define UNUSED(z) z +#define PRIVATE +#define PUBLIC +#endif + + + +#if SSLEAY_VERSION_NUMBER < 0x0090581fL +#define RAND_add(a,b,c) RAND_seed(a,b) +#define RAND_status() 1 +#endif + +#if SSLEAY_VERSION_NUMBER >= 0x00904100L +/* Support both OpenSSL 0.9.4 and SSLeay 0.9.0 */ +#define OPENSSL_PEM_CB(A,B) A, B +#else +#define RAND_add(a,b,c) RAND_seed(a,b) +#define OPENSSL_PEM_CB(A,B) A + +#define STACK_OF(A) STACK + +#define sk_X509_num sk_num +#define sk_X509_value (X509 *)sk_value +#define sk_X509_push(A, B) sk_push(A, (char *) B) +#define sk_X509_insert(A,B,C) sk_insert(A, (char *) B, C) +#define sk_X509_delete sk_delete +#define sk_X509_new_null sk_new_null +#define sk_X509_pop_free sk_pop_free + +#define sk_X509_NAME_ENTRY_num sk_num +#define sk_X509_NAME_ENTRY_value (X509_NAME_ENTRY *)sk_value + +#define sk_SSL_CIPHER_num sk_num +#define sk_SSL_CIPHER_value (SSL_CIPHER*)sk_value +#define sk_SSL_CIPHER_insert(A,B,C) sk_insert(A, (char *) B, C) +#define sk_SSL_CIPHER_delete sk_delete +#define sk_SSL_CIPHER_push(A, B) sk_push(A, (char *) B) +#define sk_SSL_CIPHER_shift(A) sk_shift(A) +#define sk_SSL_CIPHER_dup(A) sk_dup(A) +#define sk_SSL_CIPHER_unshift(A, B) sk_unshift(A, (char *) B) +#define sk_SSL_CIPHER_pop(A) sk_pop(A) +#define sk_SSL_CIPHER_delete_ptr(A, B) sk_delete_ptr(A, B) + +#define sk_X509_EXTENSION_num sk_num +#define sk_X509_EXTENSION_value (X509_EXTENSION *)sk_value +#define sk_X509_EXTENSION_push(A, B) sk_push(A, (char *) B) +#define sk_X509_EXTENSION_new_null sk_new_null +#define sk_X509_EXTENSION_pop_free sk_pop_free + +#define sk_X509_REVOKED_num sk_num +#define sk_X509_REVOKED_value (X509_REVOKED*)sk_value + +#endif + +#include "openssl/ssl.h" +#include "openssl/err.h" +#include "openssl/bio.h" +#include "openssl/pem.h" +#include "openssl/x509.h" +#include "openssl/stack.h" + +/********************************************************************** + Define constants +**********************************************************************/ + +#define X509_CERT_DIR "X509_CERT_DIR" +#define X509_CERT_FILE "X509_CERT_FILE" +#define X509_USER_PROXY "X509_USER_PROXY" +#define X509_USER_CERT "X509_USER_CERT" +#define X509_USER_KEY "X509_USER_KEY" +#define X509_USER_DELEG_PROXY "X509_USER_DELEG_PROXY" +#define X509_USER_DELEG_FILE "x509up_p" +#define X509_USER_PROXY_FILE "x509up_u" + +/* This is added after the CA name hash to make the policy filename */ +#define SIGNING_POLICY_FILE_EXTENSION ".signing_policy" + +#ifdef WIN32 +#define GSI_REGISTRY_DIR "software\\Globus\\GSI" +#define X509_DEFAULT_CERT_DIR ".globus\\certificates" +#define X509_DEFAULT_USER_CERT ".globus\\usercert.pem" +#define X509_DEFAULT_USER_CERT_P12 ".globus\\usercert.p12" +#define X509_DEFAULT_USER_CERT_P12_GT ".globus\\usercred.p12" +#define X509_DEFAULT_USER_KEY ".globus\\userkey.pem" +#define X509_INSTALLED_CERT_DIR "share\\certificates" +#define X509_INSTALLED_HOST_CERT_DIR "NEEDS_TO_BE_DETERMINED" +#define X509_DEFAULT_HOST_CERT "NEEDS_TO_BE_DETERMINED" +#define X509_DEFAULT_HOST_KEY "NEEDS_TO_BE_DETERMINED" +#else +#define X509_DEFAULT_CERT_DIR ".globus/certificates" +#define X509_DEFAULT_USER_CERT ".globus/usercert.pem" +#define X509_DEFAULT_USER_CERT_P12 ".globus/usercert.p12" +#define X509_DEFAULT_USER_CERT_P12_GT ".globus/usercred.p12" +#define X509_DEFAULT_USER_KEY ".globus/userkey.pem" +#define X509_INSTALLED_CERT_DIR "share/certificates" +#define X509_INSTALLED_HOST_CERT_DIR "/etc/grid-security/certificates" +#define X509_DEFAULT_HOST_CERT "/etc/grid-security/hostcert.pem" +#define X509_DEFAULT_HOST_KEY "/etc/grid-security/hostkey.pem" +#endif + +/* + * To allow the use of the proxy_verify_callback with + * applications which already use the SSL_set_app_data, + * we define here the index for use with the + * SSL_set_ex_data. This is hardcoded today, but + * if needed we could add ours at the highest available, + * then look at all of them for the magic number. + * To allow for recursive calls to proxy_verify_callback + * when verifing a delegate cert_chain, we also have + * PVD_STORE_EX_DATA_IDX + */ + +#define PVD_SSL_EX_DATA_IDX 5 +#define PVD_STORE_EX_DATA_IDX 6 + + +#define PVD_MAGIC_NUMBER 22222 +#define PVXD_MAGIC_NUMBER 33333 + +/* Used by ERR_set_continue_needed as a flag for error routines */ +#define ERR_DISPLAY_CONTINUE_NEEDED 64 + +/* Location relative to ERR_LIB_USER where PRXYERR library will be stored */ +#define ERR_USER_LIB_PRXYERR_NUMBER ERR_LIB_USER + +/* + * Use the SSLeay error facility with the ERR_LIB_USER + */ + +#define PRXYerr(f,r) ERR_PUT_error(ERR_USER_LIB_PRXYERR_NUMBER,(f),(r),__FILE__,__LINE__) + +/* + * SSLeay 0.9.0 added the error_data feature. We may be running + * with 0.8.1 which does not have it, if so, define a dummy + * ERR_add_error_data and ERR_get_error_line_data + +*/ + +#if SSLEAY_VERSION_NUMBER < 0x0900 +void ERR_add_error_data( VAR_PLIST( int, num ) ); + +unsigned long ERR_get_error_line_data(char **file,int *line, + char **data, int *flags); +#endif + +void +ERR_set_continue_needed(void); + +/* + * defines for function codes our minor error codes + * These match strings defined in gsserr.c. + */ + +#define PRXYERR_F_BASE 100 + +#define PRXYERR_F_PROXY_GENREQ PRXYERR_F_BASE + 0 +#define PRXYERR_F_PROXY_SIGN PRXYERR_F_BASE + 1 +#define PRXYERR_F_VERIFY_CB PRXYERR_F_BASE + 2 +#define PRXYERR_F_PROXY_LOAD PRXYERR_F_BASE + 3 +#define PRXYERR_F_PROXY_TMP PRXYERR_F_BASE + 4 +#define PRXYERR_F_INIT_CRED PRXYERR_F_BASE + 5 +#define PRXYERR_F_LOCAL_CREATE PRXYERR_F_BASE + 6 +#define PRXYERR_F_CB_NO_PW PRXYERR_F_BASE + 7 +#define PRXYERR_F_GET_CA_SIGN_PATH PRXYERR_F_BASE + 8 +#define PRXYERR_F_PROXY_SIGN_EXT PRXYERR_F_BASE + 9 +#define PRXYERR_F_PROXY_CHECK_SUBJECT_NAME PRXYERR_F_BASE + 10 +#define PRXYERR_F_PROXY_CONSTRUCT_NAME PRXYERR_F_BASE + 11 + +/* + * defines for reasons + * The match strings defined in gsserr.c + * These are also used for the minor_status codes. + * We want to make sure these don't overlap with the errors in + * gssapi_ssleay.h. + */ + +#define PRXYERR_R_BASE 1000 + +#define PRXYERR_R_PROCESS_PROXY_KEY PRXYERR_R_BASE + 1 +#define PRXYERR_R_PROCESS_REQ PRXYERR_R_BASE + 2 +#define PRXYERR_R_PROCESS_SIGN PRXYERR_R_BASE + 3 +#define PRXYERR_R_MALFORM_REQ PRXYERR_R_BASE + 4 +#define PRXYERR_R_SIG_VERIFY PRXYERR_R_BASE + 5 +#define PRXYERR_R_SIG_BAD PRXYERR_R_BASE + 6 +#define PRXYERR_R_PROCESS_PROXY PRXYERR_R_BASE + 7 +#define PRXYERR_R_PROXY_NAME_BAD PRXYERR_R_BASE + 8 +#define PRXYERR_R_PROCESS_SIGNC PRXYERR_R_BASE + 9 +#define PRXYERR_R_BAD_PROXY_ISSUER PRXYERR_R_BASE + 10 +#define PRXYERR_R_PROBLEM_PROXY_FILE PRXYERR_R_BASE + 11 +#define PRXYERR_R_SIGN_NOT_CA PRXYERR_R_BASE + 12 +#define PRXYERR_R_PROCESS_KEY PRXYERR_R_BASE + 13 +#define PRXYERR_R_PROCESS_CERT PRXYERR_R_BASE + 14 +#define PRXYERR_R_PROCESS_CERTS PRXYERR_R_BASE + 15 +#define PRXYERR_R_NO_TRUSTED_CERTS PRXYERR_R_BASE + 16 +#define PRXYERR_R_PROBLEM_KEY_FILE PRXYERR_R_BASE + 17 +#define PRXYERR_R_USER_ZERO_LENGTH_KEY_FILE PRXYERR_R_BASE + 18 +#define PRXYERR_R_SERVER_ZERO_LENGTH_KEY_FILE PRXYERR_R_BASE + 19 +#define PRXYERR_R_ZERO_LENGTH_CERT_FILE PRXYERR_R_BASE + 20 +#define PRXYERR_R_PROBLEM_USER_NOCERT_FILE PRXYERR_R_BASE + 21 +#define PRXYERR_R_PROBLEM_SERVER_NOCERT_FILE PRXYERR_R_BASE + 22 +#define PRXYERR_R_PROBLEM_USER_NOKEY_FILE PRXYERR_R_BASE + 23 +#define PRXYERR_R_PROBLEM_SERVER_NOKEY_FILE PRXYERR_R_BASE + 24 +#define PRXYERR_R_USER_CERT_EXPIRED PRXYERR_R_BASE + 25 +#define PRXYERR_R_SERVER_CERT_EXPIRED PRXYERR_R_BASE + 26 +#define PRXYERR_R_CRL_SIGNATURE_FAILURE PRXYERR_R_BASE + 27 +#define PRXYERR_R_CRL_NEXT_UPDATE_FIELD PRXYERR_R_BASE + 28 +#define PRXYERR_R_CRL_HAS_EXPIRED PRXYERR_R_BASE + 29 +#define PRXYERR_R_CERT_REVOKED PRXYERR_R_BASE + 30 +#define PRXYERR_R_NO_HOME PRXYERR_R_BASE + 31 +#define PRXYERR_R_LPROXY_MISSED_USED PRXYERR_R_BASE + 32 +#define PRXYERR_R_LPROXY_REJECTED PRXYERR_R_BASE + 33 +#define PRXYERR_R_KEY_CERT_MISMATCH PRXYERR_R_BASE + 34 +#define PRXYERR_R_WRONG_PASSPHRASE PRXYERR_R_BASE + 35 +#define PRXYERR_R_CA_POLICY_VIOLATION PRXYERR_R_BASE + 36 +#define PRXYERR_R_CA_POLICY_RETRIEVE PRXYERR_R_BASE + 37 +#define PRXYERR_R_CA_POLICY_PARSE PRXYERR_R_BASE + 38 +#define PRXYERR_R_PROBLEM_CLIENT_CA PRXYERR_R_BASE + 39 +#define PRXYERR_R_CB_NO_PW PRXYERR_R_BASE + 40 +#define PRXYERR_R_CB_CALLED_WITH_ERROR PRXYERR_R_BASE + 41 +#define PRXYERR_R_CB_ERROR_MSG PRXYERR_R_BASE + 42 +#define PRXYERR_R_CLASS_ADD_OID PRXYERR_R_BASE + 43 +#define PRXYERR_R_CLASS_ADD_EXT PRXYERR_R_BASE + 44 +#define PRXYERR_R_DELEGATE_VERIFY PRXYERR_R_BASE + 45 +#define PRXYERR_R_EXT_ADD PRXYERR_R_BASE + 46 +#define PRXYERR_R_DELEGATE_COPY PRXYERR_R_BASE + 47 +#define PRXYERR_R_DELEGATE_CREATE PRXYERR_R_BASE + 48 +#define PRXYERR_R_BUFFER_TOO_SMALL PRXYERR_R_BASE + 49 +#define PRXYERR_R_PROXY_EXPIRED PRXYERR_R_BASE + 50 +#define PRXYERR_R_NO_PROXY PRXYERR_R_BASE + 51 +#define PRXYERR_R_CA_UNKNOWN PRXYERR_R_BASE + 52 +#define PRXYERR_R_CA_NOPATH PRXYERR_R_BASE + 53 +#define PRXYERR_R_CA_NOFILE PRXYERR_R_BASE + 54 +#define PRXYERR_R_CA_POLICY_ERR PRXYERR_R_BASE + 55 +#define PRXYERR_R_INVALID_CERT PRXYERR_R_BASE + 56 +#define PRXYERR_R_CERT_NOT_YET_VALID PRXYERR_R_BASE + 57 +#define PRXYERR_R_LOCAL_CA_UNKNOWN PRXYERR_R_BASE + 58 +#define PRXYERR_R_REMOTE_CRED_EXPIRED PRXYERR_R_BASE + 59 +#define PRXYERR_R_OUT_OF_MEMORY PRXYERR_R_BASE + 60 +#define PRXYERR_R_BAD_ARGUMENT PRXYERR_R_BASE + 61 +#define PRXYERR_R_BAD_MAGIC PRXYERR_R_BASE + 62 +#define PRXYERR_R_UNKNOWN_CRIT_EXT PRXYERR_R_BASE + 63 +/* NOTE: Don't go over 1500 here or will conflict with errors in scutils.h */ + + +/********************************************************************** + Type definitions +**********************************************************************/ + +/* proxy_verify_ctx_desc - common to all verifys */ + +typedef struct proxy_verify_ctx_desc_struct { + int magicnum ; + char * certdir; + time_t goodtill; +} proxy_verify_ctx_desc ; + +/* proxy_verify_desc - allows for recursive verifys with delegation */ + +typedef struct proxy_verify_desc_struct proxy_verify_desc; + +struct proxy_verify_desc_struct { + int magicnum; + proxy_verify_desc * previous; + proxy_verify_ctx_desc * pvxd; + int flags; + X509_STORE_CTX * cert_store; + int recursive_depth; + int proxy_depth; + int cert_depth; + int limited_proxy; + STACK_OF(X509) * cert_chain; /* X509 */ + int multiple_limited_proxy_ok; +}; + +/********************************************************************** + Global variables +**********************************************************************/ + +/********************************************************************** + Function prototypes +**********************************************************************/ + +int +ERR_load_prxyerr_strings(int i); + +int proxy_load_user_cert_and_key_pkcs12(const char *user_cert, + X509 **cert, + STACK_OF(X509) **stack, + EVP_PKEY **pkey, + int (*pw_cb) ()); + +int +proxy_get_filenames( + int proxy_in, + char ** p_cert_file, + char ** p_cert_dir, + char ** p_user_proxy, + char ** p_user_cert, + char ** p_user_key); + +int +proxy_load_user_cert( + const char * user_cert, + X509 ** certificate, + int (*pw_cb)(), + unsigned long * hSession); + +int +proxy_load_user_key( + EVP_PKEY ** private_key, + X509 * ucert, + const char * user_key, + int (*pw_cb)(), + unsigned long * hSession); + +void +proxy_verify_init( + proxy_verify_desc * pvd, + proxy_verify_ctx_desc * pvxd); + +void +proxy_verify_release( + proxy_verify_desc * pvd); + +void +proxy_verify_ctx_init( + proxy_verify_ctx_desc *pvxd); +void +proxy_verify_ctx_release( + proxy_verify_ctx_desc *pvxd); + +int +proxy_check_proxy_name( + X509 *); + +int +proxy_check_issued( + X509_STORE_CTX * ctx, + X509 * x, + X509 * issuer); + +int +proxy_verify_certchain( + STACK_OF(X509) * certchain, + proxy_verify_desc * ppvd); + +int +proxy_verify_callback( + int ok, + X509_STORE_CTX * ctx); + +int +proxy_genreq( + X509 * ucert, + X509_REQ ** reqp, + EVP_PKEY ** pkeyp, + int bits, + const char * newdn, + int (*callback)()); + +int +proxy_sign( + X509 * user_cert, + EVP_PKEY * user_private_key, + X509_REQ * req, + X509 ** new_cert, + int seconds, + STACK_OF(X509_EXTENSION) * extensions, + int limited_proxy, + int proxyver, + const char * newdn, + const char * newissuer, + int pastproxy, + const char * newserial, + int selfsigned +); + +int +proxy_sign_ext( + X509 * user_cert, + EVP_PKEY * user_private_key, + const EVP_MD * method, + X509_REQ * req, + X509 ** new_cert, + X509_NAME * subject_name, + X509_NAME * issuer_name, + int seconds, + STACK_OF(X509_EXTENSION) * extensions, + int proxyver, + int pastproxy, + const char * newserial, + int selfsigned); + +int +proxy_check_subject_name( + X509_REQ * req, + X509_NAME * subject_name); + +int +proxy_construct_name( + X509 * cert, + X509_NAME ** name, + char * newcn, + unsigned int len); + +int +proxy_marshal_tmp( + X509 * ncert, + EVP_PKEY * npkey, + X509 * ucert, + STACK_OF(X509) * store_ctx, + char ** filename); + +int +proxy_marshal_bp( + BIO * bp, + X509 * ncert, + EVP_PKEY * npkey, + X509 * ucert, + STACK_OF(X509) * store_ctx); + +int +proxy_load_user_proxy( + STACK_OF(X509) * cert_chain, + const char * file); + +int +proxy_get_base_name( + X509_NAME * subject); + +X509_EXTENSION * +proxy_extension_class_add_create( + void * buffer, + size_t length); +/* + * SSLeay does not have a compare time function + * So we add a convert to time_t function + */ + +time_t +ASN1_UTCTIME_mktime( + ASN1_UTCTIME * ctm); + +time_t ASN1_TIME_mktime(ASN1_TIME *ctm); + +int PRIVATE determine_filenames(char **cacert, char **certdir, char **outfile, + char **certfile, char **keyfile, int noregen); +int load_credentials(const char *certname, const char *keyname, + X509 **cert, STACK_OF(X509) **stack, EVP_PKEY **key, + int (*callback)()); +int PRIVATE load_certificate_from_file(FILE *file, X509 **cert, + STACK_OF(X509) **stack); + +int +proxy_app_verify_callback(X509_STORE_CTX *ctx, UNUSED(void *empty)); + +STACK_OF(X509) *load_chain(BIO *in, char*); + +int my_txt2nid(char *name); + +EXTERN_C_END + +#endif /* _SSLUTILS_H */ diff --git a/emi.canl.canl-c/src/proxy/vomsproxy.h b/emi.canl.canl-c/src/proxy/vomsproxy.h new file mode 100644 index 0000000..5284d18 --- /dev/null +++ b/emi.canl.canl-c/src/proxy/vomsproxy.h @@ -0,0 +1,103 @@ +/********************************************************************* + * + * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it + * + * Copyright (c) Members of the EGEE Collaboration. 2004-2010. + * See http://www.eu-egee.org/partners/ for details on the copyright holders. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Parts of this code may be based upon or even include verbatim pieces, + * originally written by other people, in which case the original header + * follows. + * + *********************************************************************/ + +#ifndef VOMS_PROXY_H +#define VOMS_PROXY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "newformat.h" + +struct VOMSProxyArguments { + X509_REQ *proxyrequest; + char *proxyfilename; + char *filename; + AC **aclist; + int proxyversion; + char *data; + int datalen; + char *newsubject; + int newsubjectlen; + X509 *cert; + EVP_PKEY *key; + int bits; + char *policyfile; + char *policylang; + char *policytext; + int pathlength; + int hours; + int minutes; + int limited; + char *voID; + int (*callback)(); + STACK_OF(X509_EXTENSION) *extensions; + STACK_OF(X509) *chain; + int pastproxy; + char *keyusage; + char *netscape; + char *exkusage; + char *newissuer; + char *newserial; + int selfsigned; +}; + +struct VOMSProxy { + X509 *cert; + STACK_OF(X509) *chain; + EVP_PKEY *key; +}; + +struct VOMSProxyArguments *VOMS_MakeProxyArguments(); +void VOMS_FreeProxyArguments(struct VOMSProxyArguments *args); +void VOMS_FreeProxy(struct VOMSProxy *proxy); +struct VOMSProxy *VOMS_AllocProxy(); +int VOMS_WriteProxy(const char *filename, struct VOMSProxy *proxy); +struct VOMSProxy *VOMS_MakeProxy(struct VOMSProxyArguments *args, int *warning, void **additional); +X509_EXTENSION *CreateProxyExtension(char * name, char *data, int datalen, int crit); +char *ProxyCreationError(int error, void *additional); + +#define PROXY_ERROR_IS_WARNING(error) (error >= 1000) + +#define PROXY_NO_ERROR 0 +#define PROXY_ERROR_OPEN_FILE 1 +#define PROXY_ERROR_STAT_FILE 2 +#define PROXY_ERROR_OUT_OF_MEMORY 3 +#define PROXY_ERROR_FILE_READ 4 +#define PROXY_ERROR_UNKNOWN_BIT 5 +#define PROXY_ERROR_UNKNOWN_EXTENDED_BIT 6 +#define PROXY_WARNING_GSI_ASSUMED 1000 +#define PROXY_WARNING_GENERIC_LANGUAGE_ASSUMED 1001 + +#ifdef __cplusplus +} +#endif + +#endif