import of VOMS routines to handle grid-specific stuff
authorDaniel Kouřil <kouril@ics.muni.cz>
Mon, 12 Dec 2011 12:51:35 +0000 (12:51 +0000)
committerDaniel Kouřil <kouril@ics.muni.cz>
Mon, 12 Dec 2011 12:51:35 +0000 (12:51 +0000)
21 files changed:
emi.canl.canl-c/src/proxy/config.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/doio.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/doio.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/evaluate.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/list.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/listfunc.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/myproxycertinfo.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/namespaces.l [new file with mode: 0644]
emi.canl.canl-c/src/proxy/namespaces.y [new file with mode: 0644]
emi.canl.canl-c/src/proxy/normalize.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/normalize.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/parsertypes.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/proxy.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/proxycertinfo.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/scutils.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/scutils.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/signing_policy.l [new file with mode: 0644]
emi.canl.canl-c/src/proxy/signing_policy.y [new file with mode: 0644]
emi.canl.canl-c/src/proxy/sslutils.c [new file with mode: 0644]
emi.canl.canl-c/src/proxy/sslutils.h [new file with mode: 0644]
emi.canl.canl-c/src/proxy/vomsproxy.h [new file with mode: 0644]

diff --git a/emi.canl.canl-c/src/proxy/config.h b/emi.canl.canl-c/src/proxy/config.h
new file mode 100644 (file)
index 0000000..5841d88
--- /dev/null
@@ -0,0 +1,14 @@
+#if defined(__GNUC__)
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+#define UNUSED(z)  z __attribute__ ((unused))
+#else
+#define UNUSED(z)  z
+#endif
+#define PRIVATE    __attribute__ ((visibility ("hidden")))
+#define PUBLIC     __attribute__ ((visibility ("default")))
+#else
+#define UNUSED(z)  z
+#define PRIVATE
+#define PUBLIC
+#endif
+
diff --git a/emi.canl.canl-c/src/proxy/doio.c b/emi.canl.canl-c/src/proxy/doio.c
new file mode 100644 (file)
index 0000000..671c0f4
--- /dev/null
@@ -0,0 +1,72 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+
+#include "config.h"
+
+#include <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;
+}
+
diff --git a/emi.canl.canl-c/src/proxy/doio.h b/emi.canl.canl-c/src/proxy/doio.h
new file mode 100644 (file)
index 0000000..de1d965
--- /dev/null
@@ -0,0 +1,34 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+
+#ifndef VOMS_DOIO_H
+#define VOMS_DOIO_H
+
+#include <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
diff --git a/emi.canl.canl-c/src/proxy/evaluate.c b/emi.canl.canl-c/src/proxy/evaluate.c
new file mode 100644 (file)
index 0000000..09b8ba4
--- /dev/null
@@ -0,0 +1,400 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+#include <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++;
+      }
+    }
+  }
+}
diff --git a/emi.canl.canl-c/src/proxy/list.c b/emi.canl.canl-c/src/proxy/list.c
new file mode 100644 (file)
index 0000000..27b8246
--- /dev/null
@@ -0,0 +1,69 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+
+#include <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);
+  }
+}
diff --git a/emi.canl.canl-c/src/proxy/listfunc.h b/emi.canl.canl-c/src/proxy/listfunc.h
new file mode 100644 (file)
index 0000000..bfc894f
--- /dev/null
@@ -0,0 +1,33 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#ifndef VOMS_LISTFUNC_H
+#define VOMS_LISTFUNC_H
+#include <stdlib.h>
+
+typedef void (*freefn)(void *);
+
+extern char **listadd(char **vect, char *data);
+extern void   listfree(char **vect, freefn f);
+#endif
diff --git a/emi.canl.canl-c/src/proxy/myproxycertinfo.h b/emi.canl.canl-c/src/proxy/myproxycertinfo.h
new file mode 100644 (file)
index 0000000..2840971
--- /dev/null
@@ -0,0 +1,131 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *          Valerio Venturi    - valerio.venturi@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#ifndef VOMS_PROXYCERTINFO_H
+#define VOMS_PROXYCERTINFO_H
+
+#include <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
diff --git a/emi.canl.canl-c/src/proxy/namespaces.l b/emi.canl.canl-c/src/proxy/namespaces.l
new file mode 100644 (file)
index 0000000..bfd8c84
--- /dev/null
@@ -0,0 +1,67 @@
+%{
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+#include <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
+.
+
+%%
diff --git a/emi.canl.canl-c/src/proxy/namespaces.y b/emi.canl.canl-c/src/proxy/namespaces.y
new file mode 100644 (file)
index 0000000..23e5193
--- /dev/null
@@ -0,0 +1,126 @@
+%{
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+#include <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))
+{
+}
diff --git a/emi.canl.canl-c/src/proxy/normalize.c b/emi.canl.canl-c/src/proxy/normalize.c
new file mode 100644 (file)
index 0000000..ce445e5
--- /dev/null
@@ -0,0 +1,89 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+
+#include <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
diff --git a/emi.canl.canl-c/src/proxy/normalize.h b/emi.canl.canl-c/src/proxy/normalize.h
new file mode 100644 (file)
index 0000000..0ad0ab5
--- /dev/null
@@ -0,0 +1,39 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+
+#ifndef _VOMS_NORMALIZE_H
+#define _VOMS_NORMALIZE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char *normalize(const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/emi.canl.canl-c/src/proxy/parsertypes.h b/emi.canl.canl-c/src/proxy/parsertypes.h
new file mode 100644 (file)
index 0000000..84bdbf8
--- /dev/null
@@ -0,0 +1,50 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *          Valerio Venturi    - Valerio.Venturi@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+
+#ifndef _OLDGAA_PARSERTYPES_H
+#define _OLDGAA_PARSERTYPES_H
+
+struct condition {
+  char **subjects;
+  char *original;
+  int positive;
+};
+
+#define TYPE_SIGNING   0
+#define TYPE_NAMESPACE 1
+
+struct policy {
+  char *caname;
+  int self;
+  int type;
+  struct condition **conds;
+};
+
+#define SUCCESS_PERMIT    0
+#define SUCCESS_DENY      1
+#define SUCCESS_UNDECIDED 2
+
+#endif
diff --git a/emi.canl.canl-c/src/proxy/proxy.c b/emi.canl.canl-c/src/proxy/proxy.c
new file mode 100644 (file)
index 0000000..62378bb
--- /dev/null
@@ -0,0 +1,884 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+
+#include "config.h"
+
+#include <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;
+  }
+}
diff --git a/emi.canl.canl-c/src/proxy/proxycertinfo.c b/emi.canl.canl-c/src/proxy/proxycertinfo.c
new file mode 100644 (file)
index 0000000..a944ea1
--- /dev/null
@@ -0,0 +1,511 @@
+/*********************************************************************
+ *
+ * Authors: Valerio Venturi - Valerio.Venturi@cnaf.infn.it
+ *          Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+
+#include <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;
+}
diff --git a/emi.canl.canl-c/src/proxy/scutils.c b/emi.canl.canl-c/src/proxy/scutils.c
new file mode 100644 (file)
index 0000000..2bbad60
--- /dev/null
@@ -0,0 +1,987 @@
+/**********************************************************************
+
+scutils.c
+
+Description:
+       Routines used internally to work with smart card
+       using PKCS11  
+
+**********************************************************************/
+
+/**********************************************************************
+                             Include header files
+**********************************************************************/
+//#include "config.h"
+
+#ifdef USE_PKCS11
+
+#include "scutils.h"
+#include "sslutils.h"
+
+#ifndef WIN32
+#define FILE_SEPERATOR "/"
+#else
+#define FILE_SEPERATOR "\\"
+#include <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*/
+
+
diff --git a/emi.canl.canl-c/src/proxy/scutils.h b/emi.canl.canl-c/src/proxy/scutils.h
new file mode 100644 (file)
index 0000000..1b0b311
--- /dev/null
@@ -0,0 +1,251 @@
+/**********************************************************************
+scutils.h:
+
+Description:
+       This header file used internally for smart card access via PKCS11
+       For windows we can dynamicly load, and so PKCS#11 support
+       can allways be compiled, as we now have the RSA header files
+       included from the PKCS#11 2.01 version
+       
+
+**********************************************************************/
+
+#ifndef VOMS_SCUTILS_H
+#define VOMS_SCUTILS_H
+
+/**********************************************************************
+                             Include header files
+**********************************************************************/
+#ifndef NO_GSSAPI_CONFIG_H
+#include "gssapi_config.h"
+#endif
+
+#include <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 */
diff --git a/emi.canl.canl-c/src/proxy/signing_policy.l b/emi.canl.canl-c/src/proxy/signing_policy.l
new file mode 100644 (file)
index 0000000..89fb20f
--- /dev/null
@@ -0,0 +1,68 @@
+%{
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+#include <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
+.
+                     
diff --git a/emi.canl.canl-c/src/proxy/signing_policy.y b/emi.canl.canl-c/src/proxy/signing_policy.y
new file mode 100644 (file)
index 0000000..93fab4f
--- /dev/null
@@ -0,0 +1,195 @@
+%{
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *          Valerio Venturi    - Valerio.Venturi@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+#include "config.h"
+#include <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))
+{
+}
diff --git a/emi.canl.canl-c/src/proxy/sslutils.c b/emi.canl.canl-c/src/proxy/sslutils.c
new file mode 100644 (file)
index 0000000..9dd7d09
--- /dev/null
@@ -0,0 +1,3968 @@
+/*********************************************************************
+ *
+ * Authors: Valerio Venturi - Valerio.Venturi@cnaf.infn.it
+ *          Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it
+ *
+ * Copyright (c) 2002-2009 INFN-CNAF on behalf of the EU DataGrid
+ * and EGEE I, II and III
+ * For license conditions see LICENSE file or
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+/**********************************************************************
+
+sslutils.c
+
+Description:
+        Routines used internally to implement delegation and proxy 
+        certificates for use with Globus The same file is also used
+        for the non-exportable sslk5 which allows Kerberos V5 to
+        accept SSLv3 with certificates as proof of identiy and
+        issue a TGT. 
+
+**********************************************************************/
+
+/**********************************************************************
+                             Include header files
+**********************************************************************/
+#define _GNU_SOURCE
+
+//#include "config.h"
+//#include "replace.h"
+#include "myproxycertinfo.h"
+#include "sslutils.h"
+#include "parsertypes.h"
+#include "doio.h"
+//#include "data.h"
+
+#ifdef HAVE_UNISTD_H
+#include <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;
+}
diff --git a/emi.canl.canl-c/src/proxy/sslutils.h b/emi.canl.canl-c/src/proxy/sslutils.h
new file mode 100644 (file)
index 0000000..adeff08
--- /dev/null
@@ -0,0 +1,533 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it 
+ *          Valerio Venturi    - Valerio.Venturi@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+/**********************************************************************
+sslutils.h:
+
+Description:
+        This header file used internally by the gssapi_ssleay
+        routines
+
+**********************************************************************/
+
+#ifndef VOMS_SSLUTILS_H
+#define VOMS_SSLUTILS_H
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+/**********************************************************************
+                             Include header files
+**********************************************************************/
+//#include "config.h"
+
+#include <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 */
diff --git a/emi.canl.canl-c/src/proxy/vomsproxy.h b/emi.canl.canl-c/src/proxy/vomsproxy.h
new file mode 100644 (file)
index 0000000..5284d18
--- /dev/null
@@ -0,0 +1,103 @@
+/*********************************************************************
+ *
+ * Authors: Vincenzo Ciaschini - Vincenzo.Ciaschini@cnaf.infn.it
+ *
+ * Copyright (c) Members of the EGEE Collaboration. 2004-2010.
+ * See http://www.eu-egee.org/partners/ for details on the copyright holders.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Parts of this code may be based upon or even include verbatim pieces,
+ * originally written by other people, in which case the original header
+ * follows.
+ *
+ *********************************************************************/
+
+#ifndef VOMS_PROXY_H
+#define VOMS_PROXY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <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