--- /dev/null
+#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
+
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+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;
+}
+
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <stdarg.h>
+
+extern char *snprintf_wrap(const char *format, ...);
+extern char *vsnprintf_wrap(const char *format, va_list v);
+extern int fileexists(const char*);
+#endif
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <openssl/x509.h>
+#include "parsertypes.h"
+#include "doio.h"
+#include "listfunc.h"
+#include "normalize.h"
+
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+
+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++;
+ }
+ }
+ }
+}
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+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);
+ }
+}
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <stdlib.h>
+
+typedef void (*freefn)(void *);
+
+extern char **listadd(char **vect, char *data);
+extern void listfree(char **vect, freefn f);
+#endif
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <string.h>
+
+/* 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
--- /dev/null
+%{
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <stdlib.h>
+
+#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);
+
+<SINGLE_QUOTED>[^']*\' yytext[strlen(yytext)-1]='\0'; yylval_param->string = yytext; BEGIN(INITIAL); return SUBJECT;
+
+\" BEGIN(DOUBLE_QUOTED);
+<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
+.
+
+%%
--- /dev/null
+%{
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 <string> SUBJECT
+%token TO
+%token SELF
+%token PERMIT
+%token DENY
+%token SUBJECT_WORD
+%token ISSUER
+
+%type <policy> rule
+%type <cond> condition
+%type <integer> 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))
+{
+}
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+
+#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
--- /dev/null
+/*********************************************************************
+ *
+ * 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
--- /dev/null
+/*********************************************************************
+ *
+ * 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
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/stack.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+
+#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;
+ }
+}
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+
+#include <openssl/err.h>
+#include <openssl/asn1_mac.h>
+#include <openssl/objects.h>
+
+#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;
+}
--- /dev/null
+/**********************************************************************
+
+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 <windows.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef USE_PKCS11_DL
+#include <dlfcn.h>
+#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*/
+
+
--- /dev/null
+/**********************************************************************
+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 <stdio.h>
+#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 */
--- /dev/null
+%{
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <stdlib.h>
+
+#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);
+
+<SINGLE_QUOTED>[^']*\' yytext[strlen(yytext)-1]='\0'; yylval_param->string = yytext; BEGIN(INITIAL); return SUBJECTS;
+
+\" BEGIN(DOUBLE_QUOTED);
+<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
+.
+
--- /dev/null
+%{
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#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 <string> 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 <policy> eacl_entry
+%type <policy> access_identity
+%type <cond> realcondition
+%type <array> restrictions
+%type <policy> 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))
+{
+}
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <unistd.h>
+#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 <io.h>
+#else
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <dirent.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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; i<sk_X509_EXTENSION_num(extensions); i++)
+ {
+ extension = X509_EXTENSION_dup(
+ sk_X509_EXTENSION_value(extensions,i));
+
+ if (extension == NULL)
+ {
+ PRXYerr(PRXYERR_F_PROXY_SIGN_EXT,PRXYERR_R_DELEGATE_COPY);
+ goto err;
+ }
+
+ if (!sk_X509_EXTENSION_push(new_cert_info->extensions,
+ 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; i<n; i++)
+ {
+ revoked = (X509_REVOKED *)sk_X509_REVOKED_value(
+ crl_info->revoked,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;i<sk_X509_num(cert_chain);i++)
+ {
+ xcert = sk_X509_value(cert_chain,i);
+ if (!scert)
+ {
+ scert = xcert;
+ }
+ else
+ {
+ int j = X509_STORE_add_cert(cert_store, xcert);
+ if (!j)
+ {
+ if ((ERR_GET_REASON(ERR_peek_error()) ==
+ X509_R_CERT_ALREADY_IN_HASH_TABLE))
+ {
+ ERR_clear_error();
+ break;
+ }
+ else
+ {
+ /*DEE need errprhere */
+ goto err;
+ }
+ }
+ }
+ }
+ }
+ if ((lookup = X509_STORE_add_lookup(cert_store,
+ X509_LOOKUP_hash_dir())))
+ {
+ X509_LOOKUP_add_dir(lookup,pvd->pvxd->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<uid> 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;
+}
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#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 */
--- /dev/null
+/*********************************************************************
+ *
+ * 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 <openssl/x509.h>
+#include <openssl/stack.h>
+#include <openssl/evp.h>
+
+#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