grst_x509.c

Go to the documentation of this file.
00001 /*
00002    Copyright (c) 2002-7, Andrew McNab, University of Manchester
00003    All rights reserved.
00004 
00005    Redistribution and use in source and binary forms, with or
00006    without modification, are permitted provided that the following
00007    conditions are met:
00008 
00009    o Redistributions of source code must retain the above
00010      copyright notice, this list of conditions and the following
00011      disclaimer. 
00012    o Redistributions in binary form must reproduce the above
00013      copyright notice, this list of conditions and the following
00014      disclaimer in the documentation and/or other materials
00015      provided with the distribution. 
00016 
00017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00018    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
00019    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00020    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
00022    BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00024    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00026    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00028    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029    POSSIBILITY OF SUCH DAMAGE.
00030 
00031    ---------------------------------------------------------------
00032     For more information about GridSite: http://www.gridsite.org/
00033    ---------------------------------------------------------------
00034 */ 
00035 
00036 #ifndef _GNU_SOURCE
00037 #define _GNU_SOURCE
00038 #endif
00039 
00040 #include <stdio.h>
00041 #include <unistd.h>       
00042 #include <stdlib.h>
00043 #include <stdarg.h>
00044 #include <time.h>
00045 #include <stdarg.h>
00046 #include <dirent.h>
00047 #include <string.h>
00048 #include <strings.h>
00049 #include <pwd.h>
00050 #include <errno.h>
00051 #include <getopt.h>
00052 #include <pthread.h>
00053 
00054 #include <sys/types.h>
00055 #include <sys/stat.h>
00056 
00057 #ifndef GRST_NO_OPENSSL
00058 #include <openssl/x509.h>
00059 #include <openssl/x509v3.h>
00060 #include <openssl/err.h>
00061 #include <openssl/pem.h>
00062 
00063 #include <openssl/rsa.h>
00064 #include <openssl/pem.h>
00065 #include <openssl/err.h>
00066 #include <openssl/evp.h>
00067 #include <openssl/bio.h>    
00068 #include <openssl/des.h>    
00069 #include <openssl/rand.h>
00070 #endif
00071 
00072 #include "gridsite.h"
00073 
00074 #define GRST_KEYSIZE            512
00075 #define GRST_PROXYCACHE         "/../proxycache/"
00076 #define GRST_MAX_CHAIN_LEN      9
00077 #define GRST_BACKDATE_SECONDS   300
00078 
00079 pthread_mutex_t vomsmutex;
00080 
00081 /// Compare X509 Distinguished Name strings
00082 int GRSTx509NameCmp(char *a, char *b)
00083 ///
00084 /// This function attempts to do with string representations what
00085 /// would ideally be done with OIDs/values. In particular, we equate
00086 /// "/Email=" == "/emailAddress=" to deal with this important change
00087 /// between OpenSSL 0.9.6 and 0.9.7. 
00088 /// Other than that, it is currently the same as ordinary strcasecmp(3)
00089 /// (for consistency with EDG/LCG/EGEE gridmapdir case insensitivity.)
00090 {
00091    int   ret;
00092    char *aa, *bb, *p;
00093 
00094    if ((a == NULL) || (b == NULL)) return 1; /* NULL never matches */
00095 
00096    aa = strdup(a);
00097    while ((p = strstr(aa, "/emailAddress=")) != NULL)
00098         {
00099           memmove(&p[6], &p[13], strlen(&p[13]) + 1);
00100           p[1] = 'E';
00101         }
00102 
00103    bb = strdup(b);
00104    while ((p = strstr(bb, "/emailAddress=")) != NULL)
00105         {
00106           memmove(&p[6], &p[13], strlen(&p[13]) + 1);
00107           p[1] = 'E';
00108         }
00109 
00110    ret = strcasecmp(aa, bb);
00111 
00112    free(aa);
00113    free(bb);
00114                                                                                 
00115    return ret;
00116 }
00117 
00118 
00119 /// Check critical extensions
00120 int GRSTx509KnownCriticalExts(X509 *cert)
00121 ///
00122 /// Returning GRST_RET_OK if all of extensions are known to us or 
00123 /// OpenSSL; GRST_REF_FAILED otherwise.   
00124 ///
00125 /// Since this function relies on functionality (X509_supported_extension)
00126 /// introduced in 0.9.7, then we do nothing and report an error 
00127 /// (GRST_RET_FAILED) if one of the associated defines 
00128 /// (X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) is absent.
00129 {
00130    int  i;
00131    char s[80];
00132    X509_EXTENSION *ex;
00133    
00134 #ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION        
00135    for (i = 0; i < X509_get_ext_count(cert); ++i)
00136       {
00137         ex = X509_get_ext(cert, i);
00138 
00139         if (X509_EXTENSION_get_critical(ex) &&
00140                                  !X509_supported_extension(ex))
00141           {
00142             OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(ex), 1);
00143             if ( (strcmp(s, GRST_PROXYCERTINFO_OID) != 0) && 
00144                  (strcmp(s, GRST_PROXYCERTNEWINFO_OID) != 0) )
00145               return GRST_RET_FAILED;
00146           }
00147       }
00148 
00149    return GRST_RET_OK;
00150 #else
00151    return GRST_RET_FAILED;
00152 #endif
00153 }
00154 
00155 /// Check if certificate can be used as a CA to sign standard X509 certs
00156 int GRSTx509IsCA(X509 *cert)
00157 ///
00158 /// Return GRST_RET_OK if true; GRST_RET_FAILED if not.
00159 {
00160    int purpose_id;
00161 
00162    purpose_id = X509_PURPOSE_get_by_sname("sslclient");
00163 
00164    /* final argument to X509_check_purpose() is whether to check for CAness */   
00165    if (X509_check_purpose(cert, purpose_id + X509_PURPOSE_MIN, 1))
00166         return GRST_RET_OK;
00167    else return GRST_RET_FAILED;
00168 }   
00169 
00170 int GRSTx509ChainFree(GRSTx509Chain *chain)
00171 {
00172    GRSTx509Cert *grst_cert, *next_grst_cert;
00173 
00174    if (chain == NULL) return GRST_RET_OK;
00175 
00176    next_grst_cert = chain->firstcert; 
00177    
00178    while (next_grst_cert != NULL)
00179       {
00180         grst_cert = next_grst_cert;
00181         
00182         if (grst_cert->issuer != NULL) free(grst_cert->issuer);
00183         if (grst_cert->dn     != NULL) free(grst_cert->dn);
00184         if (grst_cert->ocsp   != NULL) free(grst_cert->ocsp);
00185         
00186         next_grst_cert = grst_cert->next;
00187         free(grst_cert);        
00188       }
00189 
00190    free(chain);
00191 
00192    return GRST_RET_OK;
00193 }
00194 
00195 /// Check a specific signature against a specific (VOMS) cert
00196 static int GRSTx509VerifySig(time_t *time1_time, time_t *time2_time,
00197                              unsigned char *txt, int txt_len,
00198                              unsigned char *sig, int sig_len, 
00199                              X509 *cert)
00200 ///
00201 /// Returns GRST_RET_OK if signature is ok, other values if not.
00202 {   
00203    int            ret;
00204    EVP_PKEY      *prvkey;
00205    EVP_MD_CTX     ctx;
00206    time_t         voms_service_time1, voms_service_time2;
00207 
00208    prvkey = X509_extract_key(cert);
00209    if (prvkey == NULL) {
00210      return GRST_RET_FAILED;
00211    }
00212             
00213    OpenSSL_add_all_digests();
00214 #if OPENSSL_VERSION_NUMBER >= 0x0090701fL
00215    EVP_MD_CTX_init(&ctx);
00216    EVP_VerifyInit_ex(&ctx, EVP_md5(), NULL);
00217 #else
00218    EVP_VerifyInit(&ctx, EVP_md5());
00219 #endif
00220           
00221    EVP_VerifyUpdate(&ctx, txt, txt_len);
00222 
00223    ret = EVP_VerifyFinal(&ctx, sig, sig_len, prvkey);
00224 
00225 #if OPENSSL_VERSION_NUMBER >= 0x0090701fL
00226    EVP_MD_CTX_cleanup(&ctx);      
00227 #endif
00228    EVP_PKEY_free(prvkey);
00229 
00230    if (ret != 1) {
00231      return GRST_RET_FAILED;
00232    }
00233 
00234    voms_service_time1 =
00235            GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(cert)),0);
00236           if (voms_service_time1 > *time1_time) 
00237                              *time1_time = voms_service_time1; 
00238            
00239    voms_service_time2 =
00240            GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(cert)),0);
00241           if (voms_service_time2 < *time1_time) 
00242                              *time2_time = voms_service_time2;
00243 
00244    return GRST_RET_OK ; /* verified */
00245 }
00246 
00247 /// Check the signature of the VOMS attributes
00248 static int GRSTx509VerifyVomsSig(time_t *time1_time, time_t *time2_time,
00249                                  unsigned char *asn1string, 
00250                                  struct GRSTasn1TagList taglist[], 
00251                                  int lasttag,
00252                                  char *vomsdir, int acnumber)
00253 ///
00254 /// Returns GRST_RET_OK if signature is ok, other values if not.
00255 {   
00256 #define GRST_ASN1_COORDS_VOMS_DN   "-1-1-%d-1-3-1-1-1-%%d-1-%%d"
00257 #define GRST_ASN1_COORDS_VOMS_INFO "-1-1-%d-1"
00258 #define GRST_ASN1_COORDS_VOMS_SIG  "-1-1-%d-3"
00259    int            isig, iinfo;
00260    char           certpath[16384], certpath2[16384], acvomsdn[200], dn_coords[200],
00261                   info_coords[200], sig_coords[200];
00262 
00263    DIR           *vomsDIR, *vomsDIR2;
00264    struct dirent *vomsdirent, *vomsdirent2;
00265    X509          *cert;
00266 
00267    FILE          *fp;
00268    struct stat    statbuf;
00269    static int    voms_mutex_init=0;
00270 
00271    if (!voms_mutex_init) {
00272      // initialize a protection mutex
00273      voms_mutex_init = 1;
00274      pthread_mutex_init(&vomsmutex,NULL);
00275    }
00276 
00277    pthread_mutex_lock(&vomsmutex);
00278 
00279    if ((vomsdir == NULL) || (vomsdir[0] == '\0')) {
00280      pthread_mutex_unlock(&vomsmutex);
00281      return GRST_RET_FAILED;
00282    }
00283 
00284    snprintf(dn_coords, sizeof(dn_coords),
00285             GRST_ASN1_COORDS_VOMS_DN, acnumber);
00286    
00287    if (GRSTasn1GetX509Name(acvomsdn, sizeof(acvomsdn), dn_coords,
00288                            (char*)asn1string, taglist, lasttag) != GRST_RET_OK) {
00289      pthread_mutex_unlock(&vomsmutex);
00290      return GRST_RET_FAILED;
00291    }
00292          
00293    snprintf(info_coords, sizeof(info_coords),
00294             GRST_ASN1_COORDS_VOMS_INFO, acnumber);
00295    iinfo = GRSTasn1SearchTaglist(taglist, lasttag, info_coords);
00296 
00297    snprintf(sig_coords, sizeof(sig_coords), 
00298             GRST_ASN1_COORDS_VOMS_SIG, acnumber);
00299    isig  = GRSTasn1SearchTaglist(taglist, lasttag, sig_coords);
00300 
00301    if ((iinfo < 0) || (isig < 0)) {
00302      pthread_mutex_unlock(&vomsmutex);
00303      return GRST_RET_FAILED;
00304    }
00305 
00306    vomsDIR = opendir(vomsdir);
00307    if (vomsDIR == NULL) {
00308      pthread_mutex_unlock(&vomsmutex);
00309      return GRST_RET_FAILED;
00310    }
00311 
00312    while ((vomsdirent = readdir(vomsDIR)) != NULL)
00313         {
00314           if (vomsdirent->d_name[0] == '.') continue;
00315         
00316           sprintf(certpath, "%s/%s", vomsdir, vomsdirent->d_name);
00317           stat(certpath, &statbuf);
00318           
00319           if (S_ISDIR(statbuf.st_mode))
00320             {
00321               vomsDIR2 = opendir(certpath);
00322               GRSTerrorLog(GRST_LOG_DEBUG, 
00323                            "Descend VOMS subdirectory %s", certpath);
00324               
00325               if (vomsDIR2 == NULL) continue;
00326                 
00327 
00328               while ((vomsdirent2 = readdir(vomsDIR2)) != NULL)
00329                 {
00330                   if (vomsdirent2->d_name[0] == '.') continue;
00331                   
00332                   sprintf(certpath2, "%s/%s/%s", 
00333                            vomsdir, vomsdirent->d_name, vomsdirent2->d_name);
00334                 
00335                   fp = fopen(certpath2, "r");
00336                   GRSTerrorLog(GRST_LOG_DEBUG, 
00337                                "Examine VOMS cert %s", certpath2);
00338                   if (fp == NULL) continue;
00339 
00340                   cert = PEM_read_X509(fp, NULL, NULL, NULL);
00341                   fclose(fp);
00342                   if (cert == NULL) continue;
00343 
00344                   if (GRSTx509VerifySig(time1_time, time2_time,
00345                             &asn1string[taglist[iinfo].start], 
00346                             taglist[iinfo].length+taglist[iinfo].headerlength,
00347                             &asn1string[taglist[isig].start+
00348                                                 taglist[isig].headerlength+1],
00349                             taglist[isig].length - 1,
00350                             cert) == GRST_RET_OK)
00351                     {
00352                       GRSTerrorLog(GRST_LOG_DEBUG, " VOMS cert signature match");
00353                       X509_free(cert);
00354                       closedir(vomsDIR2);
00355                       closedir(vomsDIR);
00356                       pthread_mutex_unlock(&vomsmutex);
00357                       return GRST_RET_OK ; /* verified */
00358                     }
00359             
00360                   X509_free(cert);
00361                 }
00362                 
00363               closedir(vomsDIR2);
00364             }
00365           else
00366             {
00367               fp = fopen(certpath, "r");
00368               GRSTerrorLog(GRST_LOG_DEBUG, "Examine VOMS cert %s", certpath);
00369               if (fp == NULL) continue;
00370 
00371               cert = PEM_read_X509(fp, NULL, NULL, NULL);
00372               fclose(fp);
00373               if (cert == NULL) continue;
00374 
00375               if (GRSTx509VerifySig(time1_time, time2_time,
00376                             &asn1string[taglist[iinfo].start], 
00377                             taglist[iinfo].length+taglist[iinfo].headerlength,
00378                             &asn1string[taglist[isig].start+
00379                                                 taglist[isig].headerlength+1],
00380                             taglist[isig].length - 1,
00381                             cert) == GRST_RET_OK)
00382                 {
00383                   X509_free(cert);
00384                   closedir(vomsDIR);
00385                   pthread_mutex_unlock(&vomsmutex);
00386                   return GRST_RET_OK ; /* verified */
00387                 }
00388             
00389               X509_free(cert);
00390             }
00391         }
00392 
00393    closedir(vomsDIR);   
00394    pthread_mutex_unlock(&vomsmutex);
00395    return GRST_RET_FAILED;
00396 }
00397 
00398 /// Get the VOMS attributes in the given extension
00399 static int GRSTx509ChainVomsAdd(GRSTx509Cert **grst_cert, 
00400                          time_t time1_time, time_t time2_time,
00401                          X509_EXTENSION *ex, 
00402                          char *ucuserdn, char *vomsdir)
00403 ///
00404 /// Add any VOMS credentials found into the chain. Always returns GRST_RET_OK
00405 /// - even for invalid credentials, which are flagged in errors field
00406 {
00407 #define MAXTAG 500
00408 #define GRST_ASN1_COORDS_FQAN    "-1-1-%d-1-7-1-2-1-2-%d"
00409 #define GRST_ASN1_COORDS_USER_DN "-1-1-%d-1-2-1-1-1-1-%%d-1-%%d"
00410 #define GRST_ASN1_COORDS_VOMS_DN "-1-1-%d-1-3-1-1-1-%%d-1-%%d"
00411 #define GRST_ASN1_COORDS_TIME1   "-1-1-%d-1-6-1"
00412 #define GRST_ASN1_COORDS_TIME2   "-1-1-%d-1-6-2"
00413    ASN1_OCTET_STRING *asn1data;
00414    char              *asn1string, acuserdn[200], acvomsdn[200],
00415                       dn_coords[200], fqan_coords[200], time1_coords[200],
00416                       time2_coords[200];
00417    long               asn1length;
00418    int                lasttag=-1, itag, i, acnumber = 1, chain_errors = 0;
00419    struct GRSTasn1TagList taglist[MAXTAG+1];
00420    time_t             actime1 = 0, actime2 = 0, time_now;
00421 
00422    asn1data   = X509_EXTENSION_get_data(ex);
00423    asn1string = (char*)ASN1_STRING_data(asn1data);
00424    asn1length = ASN1_STRING_length(asn1data);
00425 
00426    GRSTasn1ParseDump(NULL, (unsigned char*) asn1string, asn1length, taglist, MAXTAG, &lasttag);
00427 
00428    for (acnumber = 1; ; ++acnumber) /* go through ACs one by one */
00429       {
00430         chain_errors = 0;
00431       
00432         snprintf(dn_coords, sizeof(dn_coords), GRST_ASN1_COORDS_USER_DN, acnumber);
00433         if (GRSTasn1GetX509Name(acuserdn, sizeof(acuserdn), dn_coords,
00434                                 asn1string, taglist, lasttag) != GRST_RET_OK)
00435                              break;
00436 
00437         snprintf(dn_coords, sizeof(dn_coords), GRST_ASN1_COORDS_VOMS_DN, acnumber);
00438         if (GRSTasn1GetX509Name(acvomsdn, sizeof(acvomsdn), dn_coords,
00439                                 asn1string, taglist, lasttag) != GRST_RET_OK)
00440                              break;
00441 
00442         if (GRSTx509NameCmp(ucuserdn, acuserdn) != 0)
00443                              chain_errors |= GRST_CERT_BAD_CHAIN;
00444 
00445         if (GRSTx509VerifyVomsSig(&time1_time, &time2_time,
00446                               (unsigned char*)asn1string, taglist, lasttag, vomsdir, acnumber)
00447                               != GRST_RET_OK)
00448                              chain_errors |= GRST_CERT_BAD_SIG; 
00449 
00450         snprintf(time1_coords, sizeof(time1_coords), GRST_ASN1_COORDS_TIME1, acnumber);
00451         itag = GRSTasn1SearchTaglist(taglist, lasttag, time1_coords);
00452         
00453         if (itag > -1) actime1 = GRSTasn1TimeToTimeT((unsigned char*)
00454                                    &asn1string[taglist[itag].start+
00455                                                taglist[itag].headerlength],
00456                                    taglist[itag].length);
00457         else actime1 = 0;
00458         
00459         snprintf(time2_coords, sizeof(time2_coords), GRST_ASN1_COORDS_TIME2, acnumber);
00460         itag = GRSTasn1SearchTaglist(taglist, lasttag, time2_coords);
00461         
00462         if (itag > -1) actime2 = GRSTasn1TimeToTimeT((unsigned char*)
00463                                    &asn1string[taglist[itag].start+
00464                                                taglist[itag].headerlength],
00465                                    taglist[itag].length);
00466         else actime2 = 0;
00467         
00468         if (actime1 > time1_time) time1_time = actime1;
00469         if (actime2 < time2_time) time2_time = actime2;
00470 
00471         time(&time_now);
00472         if ((time1_time > time_now + 300) || (time2_time < time_now))
00473                chain_errors |= GRST_CERT_BAD_TIME;
00474 
00475         for (i=1; ; ++i) /* now go through FQANs */
00476            {
00477              snprintf(fqan_coords, sizeof(fqan_coords), GRST_ASN1_COORDS_FQAN, acnumber, i);
00478              itag = GRSTasn1SearchTaglist(taglist, lasttag, fqan_coords);
00479 
00480              if (itag > -1)
00481                {
00482                  (*grst_cert)->next = malloc(sizeof(GRSTx509Cert));
00483                  *grst_cert = (*grst_cert)->next;
00484                  bzero(*grst_cert, sizeof(GRSTx509Cert));
00485                
00486                  (*grst_cert)->notbefore = time1_time;
00487                  (*grst_cert)->notafter  = time2_time;
00488                  sprintf(((*grst_cert)->value), "%.*s",
00489                           taglist[itag].length,
00490                           &asn1string[taglist[itag].start+
00491                                       taglist[itag].headerlength]);
00492                                       
00493                  (*grst_cert)->errors = chain_errors; /* ie may be invalid */
00494                  (*grst_cert)->type = GRST_CERT_TYPE_VOMS;
00495                  (*grst_cert)->issuer = strdup(acvomsdn);
00496                  (*grst_cert)->dn = strdup(acuserdn);
00497                }
00498              else break;
00499            }
00500       }
00501       
00502    return GRST_RET_OK;
00503 }
00504 
00505 /// Check certificate chain for GSI proxy acceptability.
00506 int GRSTx509ChainLoadCheck(GRSTx509Chain **chain, 
00507                            STACK_OF(X509) *certstack, X509 *lastcert,
00508                            char *capath, char *vomsdir)
00509 ///
00510 /// Returns GRST_RET_OK if valid; OpenSSL X509 errors otherwise.
00511 ///
00512 /// The GridSite version handles old and new style Globus proxies, and
00513 /// proxies derived from user certificates issued with "X509v3 Basic
00514 /// Constraints: CA:FALSE" (eg UK e-Science CA)
00515 ///
00516 /// TODO: we do not yet check ProxyCertInfo and ProxyCertPolicy extensions
00517 ///       (although via GRSTx509KnownCriticalExts() we can accept them.)
00518 {
00519    X509 *cert;                  /* Points to the current cert in the loop */
00520    X509 *cacert = NULL;         /* The CA root cert */
00521    int depth = 0;               /* Depth of cert chain */
00522    int chain_errors = 0;        /* records previous errors */
00523    int first_non_ca;            /* number of the EEC issued to user by CA */
00524    char *ucuserdn = NULL;       /* DN of EEC issued to user by CA */
00525    size_t len,len2;             /* Lengths of issuer and cert DN */
00526    int IsCA;                    /* Holds whether cert is allowed to sign */
00527    int prevIsCA;                /* Holds whether previous cert in chain is 
00528                                    allowed to sign */
00529    int prevIsLimited;           /* previous cert was proxy and limited */
00530    int i,j,ret;                 /* Iteration/temp variables */
00531    char *proxy_part_DN;         /* Pointer to end part of current-cert-in-chain
00532                                    maybe eg "/CN=proxy" */
00533    char s[80];
00534    char cacertpath[16384];
00535    unsigned long subjecthash = 0;       /* hash of the name of first cert */
00536    unsigned long issuerhash = 0;        /* hash of issuer name of first cert */
00537    FILE *fp;
00538    X509_EXTENSION *ex;
00539    time_t now;
00540    GRSTx509Cert *grst_cert, *new_grst_cert;
00541    grst_cert = NULL;
00542    new_grst_cert = NULL;
00543    GRSTerrorLog(GRST_LOG_DEBUG, "GRSTx509ChainLoadCheck() starts");
00544 
00545    time(&now);
00546 
00547    first_non_ca = 0; /* set to something predictable if things fail */
00548  
00549    /* Set necessary preliminary values */
00550    IsCA          = TRUE;           /* =prevIsCA - start from a CA */
00551    prevIsLimited = 0;
00552  
00553    /* Get the client cert chain */
00554    if (certstack != NULL) 
00555      depth = sk_X509_num(certstack); /* How deep is that chain? */
00556    
00557    if ((depth == 0) && (lastcert == NULL)) 
00558      {
00559        *chain = NULL;
00560        return GRST_RET_FAILED;
00561      }
00562 
00563    cert = sk_X509_value(certstack, depth - 1);
00564    subjecthash = X509_NAME_hash(X509_get_subject_name(cert));
00565    issuerhash = X509_NAME_hash(X509_get_issuer_name(cert));
00566    sprintf(cacertpath, "%s/%.8x.0", capath, (int)issuerhash);
00567    
00568    GRSTerrorLog(GRST_LOG_DEBUG, "Look for CA root file %s", cacertpath);
00569 
00570    fp = fopen(cacertpath, "r");
00571 
00572    if (fp == NULL) chain_errors |= GRST_CERT_BAD_CHAIN;
00573    else
00574      {
00575        cacert = PEM_read_X509(fp, NULL, NULL, NULL);
00576        fclose(fp);
00577        if (cacert != NULL) { 
00578          GRSTerrorLog(GRST_LOG_DEBUG, "Loaded CA root cert from file");
00579        } else {
00580          GRSTerrorLog(GRST_LOG_DEBUG, "Failed to load CA root cert file");
00581        }
00582      }
00583 
00584    //   *chain = (GRSTx509Chain*) malloc(sizeof(GRSTx509Chain));
00585    *chain = malloc(sizeof(GRSTx509Chain));
00586    bzero(*chain, sizeof(GRSTx509Chain));
00587 
00588    /* Check the client chain */
00589    for (i = depth - ((subjecthash == issuerhash) ? 1 : 0);
00590         i >= ((lastcert == NULL) ? 0 : -1); 
00591         --i) 
00592       /* loop through client-presented chain starting at CA end */
00593       {
00594         GRSTerrorLog(GRST_LOG_DEBUG, "Process cert at depth %d in chain", i);
00595 
00596         prevIsCA=IsCA;
00597 
00598         new_grst_cert = malloc(sizeof(GRSTx509Cert));
00599         bzero(new_grst_cert, sizeof(GRSTx509Cert));
00600         new_grst_cert->errors = chain_errors;
00601         
00602         if ((*chain)->firstcert == NULL)
00603           {
00604             GRSTerrorLog(GRST_LOG_DEBUG, "Initialise chain");
00605             (*chain)->firstcert = new_grst_cert;
00606           }
00607         else grst_cert->next = new_grst_cert;
00608 
00609         grst_cert = new_grst_cert;
00610 
00611         /* Choose X509 certificate and point to it with 'cert' */
00612         if (i < 0) cert = lastcert;
00613         else if (i == depth)
00614              cert = cacert; /* the self-signed CA from the store*/
00615         else if ((i == depth - 1) && (subjecthash == issuerhash))
00616              cert = cacert; /* ie claims to be a copy of a self-signed CA */
00617         else cert = sk_X509_value(certstack, i);
00618 
00619         if (cert != NULL)
00620           {
00621             if ((i == depth - 1) && (subjecthash != issuerhash))
00622               {
00623                 /* if first cert does not claim to be a self-signed copy 
00624                    of a CA root cert in the store, we check the signature */
00625 
00626                 if (cacert == NULL)
00627                   {
00628                     chain_errors |= GRST_CERT_BAD_CHAIN;
00629                     ret = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
00630                   }
00631                 else 
00632                   {
00633                     ret = X509_check_issued(cacert, cert);
00634 
00635                     GRSTerrorLog(GRST_LOG_DEBUG, 
00636                              "Cert sig check %d returns %d", i, ret);
00637 
00638                     if (ret != X509_V_OK) 
00639                              new_grst_cert->errors |= GRST_CERT_BAD_SIG;
00640                   }
00641               }
00642             else if ((i == depth - 2) && (subjecthash == issuerhash))
00643               {
00644                 /* first cert claimed to be a self-signed copy of a CA root
00645                 cert in the store, we check the signature of the second
00646                 cert, using OUR copy of the CA cert DIRECT from the store */
00647 
00648                 if (cacert == NULL)
00649                   {
00650                     chain_errors |= GRST_CERT_BAD_CHAIN;
00651                     ret = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
00652                   }
00653                 else 
00654                   {
00655                     ret = X509_check_issued(cacert, cert);
00656                 
00657                     GRSTerrorLog(GRST_LOG_DEBUG, 
00658                              "Cert sig check %d returns %d", i, ret);
00659                 
00660                     if (ret != X509_V_OK)
00661                              new_grst_cert->errors |= GRST_CERT_BAD_SIG;
00662                   }
00663               }
00664             else if (i < depth - 1)
00665               {
00666                 /* otherwise a normal part of the chain: note that if the
00667                    first cert claims to be a self-signed copy of a CA root
00668                    cert in the store, we never use it for sig checking */
00669               
00670                 ret = X509_check_issued(sk_X509_value(certstack, i + 1), cert);
00671                 
00672                 GRSTerrorLog(GRST_LOG_DEBUG, 
00673                              "Cert sig check %d returns %d", i, ret);
00674 
00675                 if ((ret != X509_V_OK) &&
00676                     (ret != X509_V_ERR_KEYUSAGE_NO_CERTSIGN))                
00677                           new_grst_cert->errors |= GRST_CERT_BAD_SIG;
00678                           
00679                 /* NO_CERTSIGN can still be ok due to Proxy Certificates */
00680               }
00681 
00682             new_grst_cert->serial = (int) ASN1_INTEGER_get(
00683                                X509_get_serialNumber(cert));
00684             new_grst_cert->notbefore = GRSTasn1TimeToTimeT(
00685                                ASN1_STRING_data(X509_get_notBefore(cert)), 0);
00686             new_grst_cert->notafter  = GRSTasn1TimeToTimeT(
00687                                ASN1_STRING_data(X509_get_notAfter(cert)), 0);
00688           
00689             /* we check times and record if invalid */
00690           
00691             if (now < new_grst_cert->notbefore)
00692                  new_grst_cert->errors |= GRST_CERT_BAD_TIME;
00693 
00694             if (now > new_grst_cert->notafter)
00695                  new_grst_cert->errors |= GRST_CERT_BAD_TIME;
00696 
00697             new_grst_cert->dn = X509_NAME_oneline(X509_get_subject_name(cert),NULL,0);
00698             new_grst_cert->issuer = X509_NAME_oneline(X509_get_issuer_name(cert),NULL,0);
00699             len       = strlen(new_grst_cert->dn);
00700             len2      = strlen(new_grst_cert->issuer);
00701 
00702             /* always treat a first cert from the CA files as a 
00703                CA: this is really for lousy CAs that dont create 
00704                proper v3 root certificates */
00705                 
00706             if (i == depth) 
00707               IsCA = TRUE;
00708             else 
00709               IsCA = (GRSTx509IsCA(cert) == GRST_RET_OK);
00710 
00711             /* If any forebear certificate is not allowed to sign we must 
00712                assume all decendents are proxies and cannot sign either */
00713             if (prevIsCA)
00714               {
00715                 if (IsCA)
00716                   {               
00717                     new_grst_cert->type = GRST_CERT_TYPE_CA;
00718                   }
00719                 else 
00720                   {
00721                     new_grst_cert->type = GRST_CERT_TYPE_EEC;
00722                     first_non_ca = i;
00723                     ucuserdn = new_grst_cert->dn;
00724                     new_grst_cert->delegation 
00725                        = (lastcert == NULL) ? i : i + 1;
00726                   }
00727               } 
00728             else 
00729               {
00730                 new_grst_cert->type = GRST_CERT_TYPE_PROXY;
00731 
00732                 IsCA = FALSE;
00733                 /* Force proxy check next iteration. Important because I can
00734                    sign any CA I create! */
00735 
00736                 new_grst_cert->delegation = (lastcert == NULL) ? i : i + 1;
00737               }
00738 
00739             if (!prevIsCA)
00740               {
00741                 /* issuer didn't have CA status, so this is (at best) a proxy:
00742                    check for bad proxy extension*/
00743 
00744                 if (prevIsLimited) /* we reject proxies of limited proxies! */
00745                   {
00746                     new_grst_cert->errors |= GRST_CERT_BAD_CHAIN;
00747                     chain_errors |= GRST_CERT_BAD_CHAIN;
00748                   }
00749               
00750                 /* User not allowed to sign shortened DN */
00751                 if (len2 > len) 
00752                   {
00753                     new_grst_cert->errors |= GRST_CERT_BAD_CHAIN;
00754                     chain_errors |= GRST_CERT_BAD_CHAIN;
00755                   }
00756                   
00757                 /* Proxy subject must begin with issuer. */
00758                 if (strncmp((const char*)new_grst_cert->dn, new_grst_cert->issuer, len2) != 0) 
00759                   {
00760                     new_grst_cert->errors  |= GRST_CERT_BAD_CHAIN;
00761                     chain_errors |= GRST_CERT_BAD_CHAIN;
00762                   }
00763 
00764                 /* Set pointer to end of base DN in cert_DN */
00765                 proxy_part_DN = &(new_grst_cert->dn[len2]);
00766 
00767                 /* First attempt at support for Old and New style GSI
00768                    proxies: /CN=anything is ok for now */
00769                 if (strncmp((const char*)proxy_part_DN, "/CN=", 4) != 0)
00770                   {
00771                     new_grst_cert->errors  |= GRST_CERT_BAD_CHAIN;
00772                     chain_errors |= GRST_CERT_BAD_CHAIN;
00773                   }
00774 
00775                 if (strncmp((const char*)proxy_part_DN, "/CN=limited proxy", 17) == 0)
00776                         prevIsLimited = 1; /* ready for next cert ... */
00777 
00778                 for (j=0; j < X509_get_ext_count(cert); ++j)
00779                    {
00780                      ex = X509_get_ext(cert, j);
00781                      OBJ_obj2txt(s,sizeof(s),X509_EXTENSION_get_object(ex),1);
00782 
00783                      if (strcmp(s, GRST_VOMS_OID) == 0) /* a VOMS extension */
00784                        {
00785                          GRSTx509ChainVomsAdd(&grst_cert, 
00786                                               new_grst_cert->notbefore,
00787                                               new_grst_cert->notafter,                                              
00788                                               ex,
00789                                               ucuserdn, 
00790                                               vomsdir);
00791                          grst_cert->delegation = (lastcert == NULL) ? i : i+1;
00792                        }
00793                    }
00794                         
00795               } 
00796           }
00797           
00798 
00799       } /* end of for loop */
00800 
00801    if (cacert != NULL) X509_free(cacert);
00802  
00803    return GRST_RET_OK;
00804 }
00805 
00806 /// Check certificate chain for GSI proxy acceptability.
00807 int GRSTx509CheckChain(int *first_non_ca, X509_STORE_CTX *ctx)
00808 ///
00809 /// Returns X509_V_OK/GRST_RET_OK if valid; OpenSSL X509 errors otherwise.
00810 ///
00811 /// Inspired by GSIcheck written by Mike Jones, SVE, Manchester Computing,
00812 /// The University of Manchester.
00813 ///
00814 /// The GridSite version handles old and new style Globus proxies, and
00815 /// proxies derived from user certificates issued with "X509v3 Basic
00816 /// Constraints: CA:FALSE" (eg UK e-Science CA)
00817 ///
00818 /// We do not check chain links between certs here: this is done by
00819 /// GRST_check_issued/X509_check_issued in mod_ssl's ssl_engine_init.c
00820 ///
00821 /// TODO: we do not yet check ProxyCertInfo and ProxyCertPolicy extensions
00822 ///       (although via GRSTx509KnownCriticalExts() we can accept them.)
00823 {
00824    STACK_OF(X509) *certstack;   /* Points to the client's cert chain */
00825    X509 *cert;                  /* Points to the client's cert */
00826    int depth;                   /* Depth of cert chain */
00827    size_t len,len2;             /* Lengths of issuer and cert DN */
00828    int IsCA;                    /* Holds whether cert is allowed to sign */
00829    int prevIsCA=TRUE;           /* Holds whether previous cert in chain is 
00830                                    allowed to sign */
00831    int prevIsLimited;           /* previous cert was proxy and limited */
00832    int i;                       /* Iteration variables */
00833    char *cert_DN;               /* Pointer to current-certificate-in-chain's 
00834                                    DN */
00835    char *issuer_DN;             /* Pointer to 
00836                                    issuer-of-current-cert-in-chain's DN */
00837    char *proxy_part_DN;         /* Pointer to end part of current-cert-in-chain
00838                                    maybe eg "/CN=proxy" */
00839    time_t now;
00840    
00841    time(&now);
00842 
00843    *first_non_ca = 0; /* set to something predictable if things fail */
00844 
00845    /* Check for context */
00846    if (!ctx) return X509_V_ERR_INVALID_CA; 
00847      /* Can't GSI-verify if there is no context. Here and throughout this
00848         function we report all errors as X509_V_ERR_INVALID_CA. */
00849  
00850    /* Set necessary preliminary values */
00851    IsCA          = TRUE;           /* =prevIsCA - start from a CA */
00852    prevIsLimited = 0;
00853  
00854    /* Get the client cert chain */
00855    certstack = X509_STORE_CTX_get_chain(ctx);     /* Get the client's chain  */
00856    depth     = sk_X509_num(certstack);            /* How deep is that chain? */
00857  
00858    /* Check the client chain */
00859    for (i=depth-1; i >= 0; --i) 
00860       /* loop through client-presented chain starting at CA end */
00861       {
00862         prevIsCA=IsCA;
00863 
00864         /* Check for X509 certificate and point to it with 'cert' */
00865         if ( (cert = sk_X509_value(certstack, i)) )
00866           {
00867             /* we check times and reject immediately if invalid */
00868           
00869             if (now <
00870            GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(cert)),0))
00871                   return X509_V_ERR_INVALID_CA;
00872                 
00873             if (now > 
00874            GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(cert)),0))
00875                   return X509_V_ERR_INVALID_CA;
00876 
00877             /* If any forebear certificate is not allowed to sign we must 
00878                assume all decendents are proxies and cannot sign either */
00879             if (prevIsCA)
00880               {
00881                 /* always treat the first cert (from the CA files) as a CA */
00882                 if (i == depth-1) IsCA = TRUE;
00883                 /* check if this cert is valid CA for signing certs */
00884                 else IsCA = (GRSTx509IsCA(cert) == GRST_RET_OK);
00885                 
00886                 if (!IsCA) *first_non_ca = i;
00887               } 
00888             else 
00889               {
00890                 IsCA = FALSE; 
00891                 /* Force proxy check next iteration. Important because I can
00892                    sign any CA I create! */
00893               }
00894  
00895             cert_DN   = X509_NAME_oneline(X509_get_subject_name(cert),NULL,0);
00896             issuer_DN = X509_NAME_oneline(X509_get_issuer_name(cert),NULL,0);
00897             len       = strlen(cert_DN);
00898             len2      = strlen(issuer_DN);
00899 
00900             /* issuer didn't have CA status, so this is (at best) a proxy:
00901                check for bad proxy extension*/
00902 
00903             if (!prevIsCA)
00904               {
00905                 if (prevIsLimited) /* we reject proxies of limited proxies! */
00906                                 return X509_V_ERR_INVALID_CA;
00907               
00908                 /* User not allowed to sign shortened DN */
00909                 if (len2 > len) return X509_V_ERR_INVALID_CA;                           
00910                   
00911                 /* Proxy subject must begin with issuer. */
00912                 if (strncmp((const char*)cert_DN, issuer_DN, len2) != 0) 
00913                               return X509_V_ERR_INVALID_CA;
00914 
00915                 /* Set pointer to end of base DN in cert_DN */
00916                 proxy_part_DN = &cert_DN[len2];
00917 
00918                 /* First attempt at support for Old and New style GSI
00919                    proxies: /CN=anything is ok for now */
00920                 if (strncmp((const char*)proxy_part_DN, "/CN=", 4) != 0)
00921                                          return X509_V_ERR_INVALID_CA;
00922                                          
00923                 if ((strncmp((const char*)proxy_part_DN, "/CN=limited proxy", 17) == 0) &&
00924                     (i > 0)) prevIsLimited = 1; /* ready for next cert ... */
00925               } 
00926           }
00927       }
00928 
00929    /* Check cert whose private key is being used by client. If previous in 
00930       chain is not allowed to be a CA then need to check this final cert for 
00931       valid proxy-icity too */
00932    if (!prevIsCA) 
00933      { 
00934        if (prevIsLimited) return X509_V_ERR_INVALID_CA;
00935         /* we do not accept proxies signed by limited proxies */
00936      
00937        if ( (cert = sk_X509_value(certstack, 0)) )
00938          {
00939            /* Load DN & length of DN and either its issuer or the
00940               first-bad-issuer-in-chain */
00941            cert_DN = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
00942            issuer_DN = X509_NAME_oneline(X509_get_issuer_name(cert),  NULL, 0);
00943            len = strlen(cert_DN);
00944            len2 = strlen(issuer_DN);
00945  
00946            /* issuer didn't have CA status, check for bad proxy extension */
00947 
00948            if (len2 > len) return X509_V_ERR_INVALID_CA;
00949              /* User not allowed to sign shortened DN */
00950 
00951            if (strncmp((const char*)cert_DN, issuer_DN, len2) != 0) 
00952                            return X509_V_ERR_INVALID_CA;
00953              /* Proxy subject must begin with issuer. */
00954 
00955            proxy_part_DN = &cert_DN[len2];                         
00956              /* Set pointer to end of DN base in cert_DN */
00957              
00958            /* Remander of subject must be either "/CN=proxy" or 
00959               "/CN=limited proxy" (or /CN=XYZ for New style GSI) */
00960               
00961            /* First attempt at support for Old and New style GSI
00962               proxies: /CN=anything is ok for now. */
00963            if (strncmp((const char*)proxy_part_DN, "/CN=", 4) != 0)
00964                                    return X509_V_ERR_INVALID_CA;
00965          }
00966      }
00967  
00968    return X509_V_OK; /* this is also GRST_RET_OK, of course - by choice */
00969 }
00970 
00971 /// Example VerifyCallback routine
00972 int GRSTx509VerifyCallback (int ok, X509_STORE_CTX *ctx)
00973 {
00974    int errnum   = X509_STORE_CTX_get_error(ctx);
00975    int errdepth = X509_STORE_CTX_get_error_depth(ctx);
00976    int first_non_ca;
00977 
00978 #ifndef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION
00979 #define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
00980 #endif
00981 
00982    if (errnum == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
00983      {
00984        if (GRSTx509KnownCriticalExts(X509_STORE_CTX_get_current_cert(ctx))
00985            == GRST_RET_OK)
00986          {
00987            ok = TRUE;
00988            errnum = X509_V_OK;
00989            X509_STORE_CTX_set_error(ctx, errnum);
00990          }                               
00991      }
00992    else if ((errdepth == 0)       && 
00993             (errnum == X509_V_OK) && 
00994             (GRSTx509CheckChain(&first_non_ca, ctx) != X509_V_OK)) ok = FALSE;
00995    
00996    
00997    return ok;
00998   
00999 // check this 
01000    
01001 //   if (ok) return GRST_RET_OK;
01002 //   else    return GRST_RET_FAILED;
01003 }
01004 
01005 /// Get the VOMS attributes in the given extension
01006 int GRSTx509ParseVomsExt(int *lastcred, int maxcreds, size_t credlen, 
01007                          char *creds, time_t time1_time, time_t time2_time,
01008                          X509_EXTENSION *ex, char *ucuserdn, char *vomsdir)
01009 ///
01010 /// Puts any VOMS credentials found into the Compact Creds string array
01011 /// starting at *creds. Always returns GRST_RET_OK - even for invalid
01012 /// credentials, which are just ignored.
01013 {
01014 #define MAXTAG 500
01015 #define GRST_ASN1_COORDS_FQAN    "-1-1-%d-1-7-1-2-1-2-%d"
01016 #define GRST_ASN1_COORDS_USER_DN "-1-1-%d-1-2-1-1-1-1-%%d-1-%%d"
01017 #define GRST_ASN1_COORDS_TIME1   "-1-1-%d-1-6-1"
01018 #define GRST_ASN1_COORDS_TIME2   "-1-1-%d-1-6-2"
01019    ASN1_OCTET_STRING *asn1data;
01020    unsigned char     *asn1string;
01021    char               acuserdn[200],
01022                       dn_coords[200], fqan_coords[200], time1_coords[200],
01023                       time2_coords[200];
01024    long               asn1length;
01025    int                lasttag=-1, itag, i, acnumber = 1;
01026    struct GRSTasn1TagList taglist[MAXTAG+1];
01027    time_t             actime1, actime2, time_now;
01028 
01029    asn1data   = X509_EXTENSION_get_data(ex);
01030    asn1string = (unsigned char*) (ASN1_STRING_data((asn1data)));
01031    asn1length = (long)ASN1_STRING_length(asn1data);
01032 
01033    GRSTasn1ParseDump(NULL, asn1string, asn1length, taglist, MAXTAG, &lasttag);
01034 
01035    for (acnumber = 1; ; ++acnumber) /* go through ACs one by one */
01036       {
01037         snprintf(dn_coords, sizeof(dn_coords), GRST_ASN1_COORDS_USER_DN, acnumber);
01038         if (GRSTasn1GetX509Name(acuserdn, sizeof(acuserdn), dn_coords,
01039                        (char*)asn1string, taglist, lasttag) != GRST_RET_OK) break;
01040 
01041         if (GRSTx509NameCmp(ucuserdn, acuserdn) != 0) continue;
01042 
01043         if (GRSTx509VerifyVomsSig(&time1_time, &time2_time,
01044                              asn1string, taglist, lasttag, vomsdir, acnumber)
01045                              != GRST_RET_OK) continue;
01046 
01047         snprintf(time1_coords, sizeof(time1_coords), GRST_ASN1_COORDS_TIME1, acnumber);
01048         itag = GRSTasn1SearchTaglist(taglist, lasttag, time1_coords);
01049         actime1 = GRSTasn1TimeToTimeT(&asn1string[taglist[itag].start+
01050                                              taglist[itag].headerlength],
01051                                  taglist[itag].length);
01052         if (actime1 > time1_time) time1_time = actime1;
01053 
01054         snprintf(time2_coords, sizeof(time2_coords), GRST_ASN1_COORDS_TIME2, acnumber);
01055         itag = GRSTasn1SearchTaglist(taglist, lasttag, time2_coords);
01056         actime2 = GRSTasn1TimeToTimeT(&asn1string[taglist[itag].start+
01057                                              taglist[itag].headerlength],
01058                                              taglist[itag].length);
01059         if (actime2 < time2_time) time2_time = actime2;
01060 
01061         time(&time_now);
01062         if ((time1_time > time_now + 300) || (time2_time < time_now))
01063                continue; /* expiration isnt invalidity ...? */
01064 
01065         for (i=1; ; ++i)
01066            {
01067              snprintf(fqan_coords, sizeof(fqan_coords), GRST_ASN1_COORDS_FQAN, acnumber, i);
01068              itag = GRSTasn1SearchTaglist(taglist, lasttag, fqan_coords);
01069 
01070              if (itag > -1)
01071                {
01072                  if (*lastcred < maxcreds - 1)
01073                    {
01074                      ++(*lastcred);
01075                      snprintf(&creds[*lastcred * (credlen + 1)], credlen+1,
01076                            "VOMS %010lu %010lu 0 %.*s", 
01077                            time1_time, time2_time, 
01078                            taglist[itag].length,
01079                            &asn1string[taglist[itag].start+
01080                                        taglist[itag].headerlength]);
01081                    }            
01082                }
01083              else break;
01084            }
01085       }
01086       
01087    return GRST_RET_OK;
01088 }
01089 
01090 /// Get the VOMS attributes in the extensions to the given cert stack
01091 int GRSTx509GetVomsCreds(int *lastcred, int maxcreds, size_t credlen, 
01092                          char *creds, X509 *usercert, STACK_OF(X509) *certstack,
01093                          char *vomsdir)
01094 ///
01095 /// Puts any VOMS credentials found into the Compact Creds string array
01096 /// starting at *creds. Always returns GRST_RET_OK.
01097 {
01098    int  i, j;
01099    char s[80];
01100    unsigned char  *ucuser;
01101    X509_EXTENSION *ex;
01102    X509           *cert;
01103    time_t          time1_time = 0, time2_time = 0, uctime1_time, uctime2_time;
01104 
01105    uctime1_time = 
01106         GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(usercert)),0);
01107    uctime2_time =       
01108         GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(usercert)),0);
01109    ucuser = (unsigned char*)
01110         X509_NAME_oneline(X509_get_subject_name(usercert), NULL, 0);
01111 
01112    for (j=sk_X509_num(certstack)-1; j >= 0; --j)
01113     {
01114       cert = sk_X509_value(certstack, j);
01115 
01116       time1_time =
01117           GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(cert)),0);
01118       uctime1_time = (time1_time > uctime1_time) ? time1_time:uctime1_time;
01119 
01120       time2_time =
01121           GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(cert)),0);
01122       uctime2_time = (time2_time < uctime2_time) ? time2_time:uctime2_time;
01123 
01124       for (i=0; i < X509_get_ext_count(cert); ++i)
01125          {
01126            ex = X509_get_ext(cert, i);
01127            OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(ex), 1);
01128 
01129            if (strcmp(s, GRST_VOMS_OID) == 0) /* a VOMS extension */
01130              {
01131                GRSTx509ParseVomsExt(lastcred, maxcreds, credlen, creds,
01132                                  uctime1_time, uctime2_time,
01133                                  ex, (char*)ucuser, vomsdir);
01134              }
01135          }
01136     }
01137 
01138    return GRST_RET_OK;
01139 }
01140 
01141 /// Turn a Compact Cred line into a GRSTgaclCred object
01142 GRSTgaclCred *GRSTx509CompactToCred(char *grst_cred)
01143 ///
01144 /// Returns pointer to created GRSTgaclCred or NULL or failure.
01145 {
01146    int       delegation;
01147    char     *p, *encoded;
01148    time_t    now, notbefore, notafter;
01149    GRSTgaclCred *cred = NULL;
01150 
01151    time(&now);
01152 
01153    if (grst_cred == NULL) return NULL; /* just in case */
01154 
01155    if (strncmp((const char*)grst_cred, "X509USER ", 9) == 0)
01156      {
01157        if ((sscanf(grst_cred, "X509USER %lu %lu %d", 
01158                               &notbefore, &notafter, &delegation) == 3)
01159             && (now >= notbefore)
01160             && (now <= notafter)
01161             && (p = index(grst_cred, ' '))
01162             && (p = index(++p, ' '))
01163             && (p = index(++p, ' '))
01164             && (p = index(++p, ' ')))
01165          {
01166            encoded = GRSThttpUrlMildencode(&p[1]);
01167            cred = GRSTgaclCredCreate("dn:", encoded);
01168            free(encoded);
01169            GRSTgaclCredSetDelegation(cred, delegation);
01170          }
01171 
01172        return cred;
01173      }
01174 
01175    if (strncmp((const char*)grst_cred, "VOMS ", 5) == 0)
01176      {
01177        if ((sscanf(grst_cred, "VOMS %lu %lu %d",
01178                               &notbefore, &notafter, &delegation) == 3)
01179             && (now >= notbefore)
01180             && (now <= notafter)
01181             && (p = index(grst_cred, ' '))
01182             && (p = index(++p, ' '))
01183             && (p = index(++p, ' '))
01184             && (p = index(++p, ' ')))
01185          {
01186            /* include /VO/group/subgroup/Role=role/Capability=cap */
01187 
01188            if (p[1] != '/') return NULL; /* must begin with / */
01189 
01190            encoded = GRSThttpUrlMildencode(&p[1]);
01191            cred = GRSTgaclCredCreate("fqan:", encoded);
01192            free(encoded);
01193            GRSTgaclCredSetDelegation(cred, delegation);
01194          }
01195 
01196        return cred;
01197      }
01198 
01199    return NULL; /* dont recognise this credential type */
01200 }
01201 
01202 /// Get the credentials in an X509 cert/GSI proxy, including any VOMS
01203 int GRSTx509CompactCreds(int *lastcred, int maxcreds, size_t credlen, 
01204                          char *creds, STACK_OF(X509) *certstack, char *vomsdir, 
01205                          X509 *peercert)
01206 ///
01207 /// Credentials are placed in Compact Creds string array at *creds.
01208 ///
01209 /// Function returns GRST_RET_OK on success, or GRST_RET_FAILED if
01210 /// some inconsistency found in certificate.
01211 {   
01212    int   i, delegation = 0;
01213    char  credtemp[credlen+1];
01214    X509 *cert, *usercert = NULL, *gsiproxycert = NULL;
01215 
01216    *lastcred = -1;
01217 
01218    for (i = sk_X509_num(certstack) - 1; i >= 0; --i) 
01219       {
01220          cert = sk_X509_value(certstack, i);
01221 
01222          if (usercert != NULL) 
01223            {           /* found a (GSI proxy) cert after the user cert */
01224              gsiproxycert = cert;
01225              ++delegation;
01226            }
01227            
01228          if ((usercert == NULL) && 
01229              (i < sk_X509_num(certstack) - 1) &&
01230              (GRSTx509IsCA(cert) != GRST_RET_OK)) usercert = cert;
01231                                           /* found the 1st non-CA cert */
01232       }
01233 
01234    if (peercert != NULL)
01235      {
01236        if (usercert != NULL) /* found a (GSI proxy) cert after user cert */
01237          {
01238            gsiproxycert = peercert;
01239            ++delegation;
01240          }
01241 
01242        if ((usercert == NULL) && 
01243            (GRSTx509IsCA(peercert) != GRST_RET_OK)) usercert = peercert;
01244                                           /* found the 1st non-CA cert */
01245      }
01246 
01247    if ((usercert == NULL) /* if no usercert ("EEC"), we're not interested */
01248        ||
01249        (snprintf(credtemp, credlen+1, "X509USER %010lu %010lu %d %s",
01250           GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(usercert)),0),
01251           GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(usercert)),0),
01252           delegation,
01253      X509_NAME_oneline(X509_get_subject_name(usercert), NULL, 0)) >= credlen+1)
01254        || 
01255        (*lastcred >= maxcreds-1))
01256      {
01257        *lastcred = -1;  /* just in case the caller looks at it */
01258        return GRST_RET_FAILED; /* tell caller that things didn't work out */
01259      }
01260 
01261    ++(*lastcred);
01262    strcpy(&creds[*lastcred * (credlen + 1)], credtemp);
01263 
01264    if ((gsiproxycert != NULL) 
01265        &&
01266        (snprintf(credtemp, credlen+1, "GSIPROXY %010lu %010lu %d %s",
01267      GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(gsiproxycert)),0), 
01268      GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(gsiproxycert)),0),
01269      delegation,
01270   X509_NAME_oneline(X509_get_subject_name(gsiproxycert), NULL, 0)) < credlen+1)
01271        &&
01272        (*lastcred < maxcreds-1))
01273      {
01274        ++(*lastcred);
01275        strcpy(&creds[*lastcred * (credlen + 1)], credtemp);
01276        GRSTx509GetVomsCreds(lastcred, maxcreds, credlen, creds, 
01277                             usercert, certstack, vomsdir);
01278      }
01279          
01280    return GRST_RET_OK;
01281 }
01282 
01283 /// Find proxy file name of the current user
01284 char *GRSTx509FindProxyFileName(void)
01285 ///
01286 /// Return a string with the proxy file name or NULL if not present.
01287 /// This function does not check if the proxy has expired.
01288 {
01289   char *p;
01290   
01291   p = getenv("X509_USER_PROXY");
01292   
01293   if (p != NULL) return strdup(p);
01294   
01295   p = malloc(sizeof("/tmp/x509up_uXYYYXXXYYY"));
01296   
01297   sprintf(p, "/tmp/x509up_u%d", getuid());  
01298 
01299   return p;
01300 }
01301 
01302 static void mpcerror(FILE *debugfp, char *msg)
01303 {
01304   if (debugfp != NULL)
01305     {
01306       fputs(msg, debugfp);
01307       ERR_print_errors_fp(debugfp);
01308     }
01309 }
01310 
01311 /// Make a GSI Proxy chain from a request, certificate and private key
01312 int GRSTx509MakeProxyCert(char **proxychain, FILE *debugfp, 
01313                           char *reqtxt, char *cert, char *key, int minutes)
01314 ///
01315 /// The proxy chain is returned in *proxychain. If debugfp is non-NULL,
01316 /// errors are output to that file pointer. The proxy will expired in
01317 /// the given number of minutes starting from the current time.
01318 {
01319   char *ptr, *certchain;
01320   int i, ncerts;
01321   long serial = 1234, ptrlen;
01322   EVP_PKEY *pkey, *CApkey;
01323   const EVP_MD *digest;
01324   X509 *certs[GRST_MAX_CHAIN_LEN];
01325   X509_REQ *req;
01326   X509_NAME *name, *CAsubject, *newsubject;
01327   X509_NAME_ENTRY *ent;
01328   FILE *fp;
01329   BIO *reqmem, *certmem;
01330   time_t notAfter;
01331 
01332   /* read in the request */
01333   reqmem = BIO_new(BIO_s_mem());
01334   BIO_puts(reqmem, reqtxt);
01335     
01336   if (!(req = PEM_read_bio_X509_REQ(reqmem, NULL, NULL, NULL)))
01337     {
01338       mpcerror(debugfp,
01339               "GRSTx509MakeProxyCert(): error reading request from BIO memory\n");
01340       BIO_free(reqmem);
01341       return GRST_RET_FAILED;
01342     }
01343     
01344   BIO_free(reqmem);
01345 
01346   /* verify signature on the request */
01347   if (!(pkey = X509_REQ_get_pubkey(req)))
01348     {
01349       mpcerror(debugfp,
01350               "GRSTx509MakeProxyCert(): error getting public key from request\n");
01351       
01352       X509_REQ_free(req);
01353       return GRST_RET_FAILED;
01354     }
01355 
01356   if (X509_REQ_verify(req, pkey) != 1)
01357     {
01358       mpcerror(debugfp,
01359             "GRSTx509MakeProxyCert(): error verifying signature on certificate\n");
01360 
01361       X509_REQ_free(req);
01362       return GRST_RET_FAILED;
01363     }
01364     
01365   /* read in the signing certificate */
01366   if (!(fp = fopen(cert, "r")))
01367     {
01368       mpcerror(debugfp,
01369             "GRSTx509MakeProxyCert(): error opening signing certificate file\n");
01370 
01371       X509_REQ_free(req);
01372       return GRST_RET_FAILED;
01373     }    
01374 
01375   for (ncerts = 1; ncerts < GRST_MAX_CHAIN_LEN; ++ncerts)
01376    if ((certs[ncerts] = PEM_read_X509(fp, NULL, NULL, NULL)) == NULL) break;
01377 
01378   if (ncerts == 1) /* zeroth cert with be new proxy cert */
01379     {
01380       mpcerror(debugfp,
01381             "GRSTx509MakeProxyCert(): error reading signing certificate file\n");
01382 
01383       X509_REQ_free(req);
01384       return GRST_RET_FAILED;
01385     }    
01386 
01387   fclose(fp);
01388   
01389   CAsubject = X509_get_subject_name(certs[1]);
01390 
01391   /* read in the CA private key */
01392   if (!(fp = fopen(key, "r")))
01393     {
01394       mpcerror(debugfp,
01395             "GRSTx509MakeProxyCert(): error reading signing private key file\n");
01396 
01397       X509_REQ_free(req);
01398       return GRST_RET_FAILED;
01399     }    
01400 
01401   if (!(CApkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)))
01402     {
01403       mpcerror(debugfp,
01404             "GRSTx509MakeProxyCert(): error reading signing private key in file\n");
01405 
01406       X509_REQ_free(req);
01407       return GRST_RET_FAILED;
01408     }    
01409 
01410   fclose(fp);
01411   
01412   /* get subject name */
01413   if (!(name = X509_REQ_get_subject_name(req)))
01414     {
01415       mpcerror(debugfp,
01416             "GRSTx509MakeProxyCert(): error getting subject name from request\n");
01417 
01418       X509_REQ_free(req);
01419       return GRST_RET_FAILED;
01420     }    
01421 
01422   /* create new certificate */
01423   if (!(certs[0] = X509_new()))
01424     {
01425       mpcerror(debugfp,
01426             "GRSTx509MakeProxyCert(): error creating X509 object\n");
01427 
01428       X509_REQ_free(req);
01429       return GRST_RET_FAILED;
01430     }    
01431 
01432   /* set version number for the certificate (X509v3) and the serial number   
01433      need 3 = v4 for GSI proxy?? */
01434   if (X509_set_version(certs[0], 3L) != 1)
01435     {
01436       mpcerror(debugfp,
01437             "GRSTx509MakeProxyCert(): error setting certificate version\n");
01438 
01439       X509_REQ_free(req);
01440       return GRST_RET_FAILED;
01441     }    
01442 
01443   ASN1_INTEGER_set(X509_get_serialNumber(certs[0]), serial++);
01444 
01445   if (!(name = X509_get_subject_name(certs[1])))
01446     {
01447       mpcerror(debugfp,
01448       "GRSTx509MakeProxyCert(): error getting subject name from CA certificate\n");
01449 
01450       X509_REQ_free(req);
01451       return GRST_RET_FAILED;
01452     }    
01453 
01454   if (X509_set_issuer_name(certs[0], name) != 1)
01455     {
01456       mpcerror(debugfp,
01457       "GRSTx509MakeProxyCert(): error setting issuer name of certificate\n");
01458 
01459       X509_REQ_free(req);
01460       return GRST_RET_FAILED;
01461     }    
01462 
01463   /* set issuer and subject name of the cert from the req and the CA */
01464   ent = X509_NAME_ENTRY_create_by_NID(NULL, OBJ_txt2nid("commonName"), 
01465                                       MBSTRING_ASC, (unsigned char*)"proxy", -1);
01466 
01467   newsubject = X509_NAME_dup(CAsubject);
01468 
01469   X509_NAME_add_entry(newsubject, ent, -1, 0);
01470 
01471   if (X509_set_subject_name(certs[0], newsubject) != 1)
01472     {
01473       mpcerror(debugfp,
01474       "GRSTx509MakeProxyCert(): error setting subject name of certificate\n");
01475 
01476       X509_REQ_free(req);
01477       return GRST_RET_FAILED;
01478     }    
01479     
01480   X509_NAME_free(newsubject);
01481   X509_NAME_ENTRY_free(ent);
01482 
01483   /* set public key in the certificate */
01484   if (X509_set_pubkey(certs[0], pkey) != 1)
01485     {
01486       mpcerror(debugfp,
01487       "GRSTx509MakeProxyCert(): error setting public key of the certificate\n");
01488 
01489       X509_REQ_free(req);
01490       return GRST_RET_FAILED;
01491     }    
01492 
01493   /* set duration for the certificate */
01494   if (!(X509_gmtime_adj(X509_get_notBefore(certs[0]), -GRST_BACKDATE_SECONDS)))
01495     {
01496       mpcerror(debugfp,
01497       "GRSTx509MakeProxyCert(): error setting beginning time of the certificate\n");
01498 
01499       X509_REQ_free(req);
01500       return GRST_RET_FAILED;
01501     }    
01502 
01503   if (!(X509_gmtime_adj(X509_get_notAfter(certs[0]), 60 * minutes)))
01504     {
01505       mpcerror(debugfp,
01506       "GRSTx509MakeProxyCert(): error setting ending time of the certificate\n");
01507 
01508       X509_REQ_free(req);
01509       return GRST_RET_FAILED;
01510     }
01511     
01512   /* go through chain making sure this proxy is not longer lived */
01513 
01514   notAfter = 
01515      GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(certs[0])), 0);
01516 
01517   for (i=1; i < ncerts; ++i)
01518        if (notAfter > 
01519            GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(certs[i])),
01520                                0))
01521          {
01522            notAfter = 
01523             GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(certs[i])),
01524                                 0);
01525             
01526            ASN1_UTCTIME_set(X509_get_notAfter(certs[0]), notAfter);
01527          }
01528 
01529   /* sign the certificate with the signing private key */
01530   if (EVP_PKEY_type(CApkey->type) == EVP_PKEY_RSA)
01531     digest = EVP_md5();
01532   else
01533     {
01534       mpcerror(debugfp,
01535       "GRSTx509MakeProxyCert(): error checking signing private key for a valid digest\n");
01536 
01537       X509_REQ_free(req);
01538       return GRST_RET_FAILED;
01539     }    
01540 
01541   if (!(X509_sign(certs[0], CApkey, digest)))
01542     {
01543       mpcerror(debugfp,
01544       "GRSTx509MakeProxyCert(): error signing certificate\n");
01545 
01546       X509_REQ_free(req);
01547       return GRST_RET_FAILED;
01548     }    
01549 
01550   /* store the completed certificate chain */
01551 
01552   certchain = strdup("");
01553 
01554   for (i=0; i < ncerts; ++i)
01555      {
01556        certmem = BIO_new(BIO_s_mem());
01557 
01558        if (PEM_write_bio_X509(certmem, certs[i]) != 1)
01559          {
01560            mpcerror(debugfp,
01561             "GRSTx509MakeProxyCert(): error writing certificate to memory BIO\n");            
01562 
01563            X509_REQ_free(req);
01564            return GRST_RET_FAILED;
01565          }
01566 
01567        ptrlen = BIO_get_mem_data(certmem, &ptr);
01568   
01569        certchain = realloc(certchain, strlen(certchain) + ptrlen + 1);
01570        
01571        strncat(certchain, ptr, ptrlen);
01572     
01573        BIO_free(certmem);
01574        X509_free(certs[i]);
01575      }
01576   
01577   EVP_PKEY_free(pkey);
01578   EVP_PKEY_free(CApkey);
01579   X509_REQ_free(req);
01580       
01581   *proxychain = certchain;  
01582   return GRST_RET_OK;
01583 }
01584 
01585 /// Find a proxy file in the proxy cache
01586 char *GRSTx509CachedProxyFind(char *proxydir, char *delegation_id, 
01587                               char *user_dn)
01588 ///
01589 /// Returns the full path and file name of proxy file associated
01590 /// with given delegation ID and user DN.
01591 ///
01592 /// Return a pointer to a malloc'd string with the full path of the 
01593 /// proxy file corresponding to the given delegation_id, or NULL
01594 /// if not found.
01595 {
01596   char *user_dn_enc;
01597   char* proxyfile = (char*)malloc(16384);
01598   struct stat statbuf;
01599 
01600   user_dn_enc = GRSThttpUrlEncode(user_dn);
01601 
01602   sprintf(proxyfile, "%s/%s/%s/userproxy.pem",
01603            proxydir, user_dn_enc, delegation_id);
01604            
01605   free(user_dn_enc);
01606 
01607   if ((stat(proxyfile, &statbuf) != 0) || !S_ISREG(statbuf.st_mode))
01608     {
01609       free(proxyfile);
01610       return NULL;
01611     }
01612     
01613   return proxyfile;
01614 }
01615 
01616 /// Find a temporary proxy private key file in the proxy cache
01617 char *GRSTx509CachedProxyKeyFind(char *proxydir, char *delegation_id, 
01618                                  char *user_dn)
01619 ///
01620 /// Returns the full path and file name of the private key file associated
01621 /// with given delegation ID and user DN.
01622 ///
01623 /// Return a pointer to a malloc'd string with the full path of the 
01624 /// private proxy key corresponding to the given delegation_id, or NULL
01625 /// if not found.
01626 {
01627   char *user_dn_enc;
01628   char* prvkeyfile = (char*) malloc(16384);
01629   struct stat statbuf;
01630 
01631   user_dn_enc = GRSThttpUrlEncode(user_dn);
01632 
01633   sprintf(prvkeyfile, "%s/cache/%s/%s/userkey.pem",
01634            proxydir, user_dn_enc, delegation_id);
01635            
01636   free(user_dn_enc);
01637 
01638   if ((stat(prvkeyfile, &statbuf) != 0) || !S_ISREG(statbuf.st_mode))
01639     {
01640       free(prvkeyfile);
01641       return NULL;
01642     }
01643     
01644   return prvkeyfile;
01645 }
01646 
01647 static void mkdir_printf(mode_t mode, char *fmt, ...)
01648 {
01649   int   ret;
01650   char path[16384];
01651   va_list ap;
01652   
01653   va_start(ap, fmt);
01654   vsprintf(path, fmt, ap);
01655   va_end(ap);
01656 
01657   ret = mkdir(path, mode);
01658 }
01659 
01660 /// Create a X.509 request for a GSI proxy and its private key
01661 int GRSTx509CreateProxyRequest(char **reqtxt, char **keytxt, char *ocspurl)
01662 ///
01663 /// Returns GRST_RET_OK on success, non-zero otherwise. Request string
01664 /// and private key are PEM encoded strings
01665 {
01666   char            *ptr;
01667   size_t           ptrlen;
01668   RSA             *keypair;
01669   X509_NAME       *subject;
01670   X509_NAME_ENTRY *ent;
01671   EVP_PKEY        *pkey;
01672   X509_REQ        *certreq;
01673   BIO             *reqmem, *keymem;
01674   const EVP_MD    *digest;
01675 
01676   /* create key pair and put it in a PEM string */
01677 
01678   if ((keypair = RSA_generate_key(GRST_KEYSIZE, 65537, NULL, NULL)) == NULL)
01679                                                                return 1;
01680 
01681   keymem = BIO_new(BIO_s_mem());
01682   if (!PEM_write_bio_RSAPrivateKey(keymem, keypair, NULL, NULL, 0, NULL, NULL))
01683     {
01684       BIO_free(keymem);
01685       return 3;
01686     }
01687 
01688   ptrlen = BIO_get_mem_data(keymem, &ptr);
01689   
01690   *keytxt = malloc(ptrlen + 1);
01691   memcpy(*keytxt, ptr, ptrlen);
01692   (*keytxt)[ptrlen] = '\0';
01693 
01694   BIO_free(keymem);
01695   
01696   /* now create the certificate request */
01697 
01698   certreq = X509_REQ_new();
01699 
01700   OpenSSL_add_all_algorithms();
01701 
01702   pkey = EVP_PKEY_new();
01703   EVP_PKEY_assign_RSA(pkey, keypair);
01704 
01705   X509_REQ_set_pubkey(certreq, pkey);
01706   
01707   subject = X509_NAME_new();
01708   ent = X509_NAME_ENTRY_create_by_NID(NULL, OBJ_txt2nid("organizationName"), 
01709                                       MBSTRING_ASC, (unsigned char*)"Dummy", -1);
01710   X509_NAME_add_entry (subject, ent, -1, 0);
01711   X509_REQ_set_subject_name (certreq, subject);
01712   
01713   digest = EVP_md5();
01714   X509_REQ_sign(certreq, pkey, digest);
01715 
01716   reqmem = BIO_new(BIO_s_mem());
01717   PEM_write_bio_X509_REQ(reqmem, certreq);
01718   ptrlen = BIO_get_mem_data(reqmem, &ptr);
01719   
01720   *reqtxt = malloc(ptrlen + 1);
01721   memcpy(*reqtxt, ptr, ptrlen);
01722   (*reqtxt)[ptrlen] = '\0';
01723 
01724   BIO_free(reqmem);
01725 
01726   X509_REQ_free(certreq);
01727   
01728   return 0;
01729 }
01730 
01731 /// Make and store a X.509 request for a GSI proxy
01732 int GRSTx509MakeProxyRequest(char **reqtxt, char *proxydir, 
01733                              char *delegation_id, char *user_dn)
01734 ///
01735 /// Returns GRST_RET_OK on success, non-zero otherwise. Request string
01736 /// is PEM encoded, and the key is stored in the temporary cache under
01737 /// proxydir
01738 {
01739   char            prvkeyfile[16384], *ptr, *user_dn_enc;
01740   size_t           ptrlen;
01741   FILE            *fp;
01742   RSA             *keypair;
01743   X509_NAME       *subject;
01744   X509_NAME_ENTRY *ent;
01745   EVP_PKEY        *pkey;
01746   X509_REQ        *certreq;
01747   BIO             *reqmem;
01748   const EVP_MD    *digest;
01749 
01750   if (strcmp(user_dn, "cache") == 0) return GRST_RET_FAILED;
01751     
01752   user_dn_enc = GRSThttpUrlEncode(user_dn);
01753 
01754   /* create directories if necessary */
01755 
01756   mkdir_printf(S_IRUSR | S_IWUSR | S_IXUSR, 
01757                "%s/cache",       proxydir);
01758   mkdir_printf(S_IRUSR | S_IWUSR | S_IXUSR, 
01759                "%s/cache/%s",    proxydir, user_dn_enc);
01760   mkdir_printf(S_IRUSR | S_IWUSR | S_IXUSR, 
01761                "%s/cache/%s/%s", proxydir, user_dn_enc, delegation_id);
01762 
01763   /* make the new proxy private key */
01764 
01765   sprintf(prvkeyfile, "%s/cache/%s/%s/userkey.pem",
01766            proxydir, user_dn_enc, delegation_id);
01767 
01768   if (prvkeyfile == NULL)  
01769     {
01770       free(user_dn_enc);
01771       return GRST_RET_FAILED;
01772     }
01773         
01774   if ((keypair = RSA_generate_key(GRST_KEYSIZE, 65537, NULL, NULL)) == NULL)
01775                                                                return 1;
01776           
01777   if ((fp = fopen(prvkeyfile, "w")) == NULL) return 2;
01778   
01779   chmod(prvkeyfile, S_IRUSR | S_IWUSR);
01780   free(user_dn_enc);
01781 
01782   if (!PEM_write_RSAPrivateKey(fp, keypair, NULL, NULL, 0, NULL, NULL))
01783                                return 3;
01784   
01785   if (fclose(fp) != 0) return 4;
01786   
01787   /* now create the certificate request */
01788 
01789   certreq = X509_REQ_new();
01790   if (certreq == NULL) return 5;
01791 
01792   OpenSSL_add_all_algorithms();
01793 
01794   pkey = EVP_PKEY_new();
01795   EVP_PKEY_assign_RSA(pkey, keypair);
01796 
01797   X509_REQ_set_pubkey(certreq, pkey);
01798   
01799   subject = X509_NAME_new();
01800   ent = X509_NAME_ENTRY_create_by_NID(NULL, OBJ_txt2nid("organizationName"), 
01801                                       MBSTRING_ASC, (unsigned char*)"Dummy", -1);
01802   X509_NAME_add_entry (subject, ent, -1, 0);
01803   X509_REQ_set_subject_name (certreq, subject);
01804   
01805   digest = EVP_md5();
01806   X509_REQ_sign(certreq, pkey, digest);
01807 
01808   reqmem = BIO_new(BIO_s_mem());
01809   PEM_write_bio_X509_REQ(reqmem, certreq);
01810   ptrlen = BIO_get_mem_data(reqmem, &ptr);
01811   
01812   *reqtxt = malloc(ptrlen + 1);
01813   memcpy(*reqtxt, ptr, ptrlen);
01814   (*reqtxt)[ptrlen] = '\0';
01815 
01816   BIO_free(reqmem);
01817 
01818   X509_REQ_free(certreq);
01819   
01820   return 0;
01821 }
01822 
01823 /// Destroy stored GSI proxy files
01824 int GRSTx509ProxyDestroy(char *proxydir, char *delegation_id, char *user_dn)
01825 ///
01826 /// Returns GRST_RET_OK on success, non-zero otherwise.
01827 /// (Including GRST_RET_NO_SUCH_FILE if the private key or cert chain
01828 ///  were not found.)
01829 {
01830   int              ret = GRST_RET_OK;
01831   char            filename[16384], *user_dn_enc;
01832 
01833   if (strcmp(user_dn, "cache") == 0) return GRST_RET_FAILED;
01834     
01835   user_dn_enc = GRSThttpUrlEncode(user_dn);
01836 
01837   /* proxy file */
01838   
01839   sprintf(filename, "%s/%s/%s/userproxy.pem",
01840            proxydir, user_dn_enc, delegation_id);
01841 
01842   if (unlink(filename) != 0) ret = GRST_RET_NO_SUCH_FILE;  
01843 
01844   /* voms file */
01845   
01846   sprintf(filename, "%s/%s/%s/voms.attributes",
01847            proxydir, user_dn_enc, delegation_id);
01848 
01849   unlink(filename);
01850   
01851   return ret;
01852 }
01853 
01854 /// Get start and finish validity times of stored GSI proxy file
01855 int GRSTx509ProxyGetTimes(char *proxydir, char *delegation_id, char *user_dn, 
01856                           time_t *start, time_t *finish)
01857 ///
01858 /// Returns GRST_RET_OK on success, non-zero otherwise.
01859 /// (Including GRST_RET_NO_SUCH_FILE if the cert chain was not found.)
01860 {
01861   char  filename[16384], *user_dn_enc;
01862   FILE  *fp;
01863   X509  *cert;
01864 
01865   if (strcmp(user_dn, "cache") == 0) return GRST_RET_FAILED;
01866     
01867   user_dn_enc = GRSThttpUrlEncode(user_dn);
01868   
01869   sprintf(filename, "%s/%s/%s/userproxy.pem",
01870            proxydir, user_dn_enc, delegation_id);
01871            
01872   free(user_dn_enc);
01873 
01874   if (filename == NULL) return GRST_RET_FAILED;
01875 
01876   fp = fopen(filename, "r");
01877   
01878   if (fp == NULL) return GRST_RET_NO_SUCH_FILE;
01879 
01880   cert = PEM_read_X509(fp, NULL, NULL, NULL); /* first cert is X.509 PC */
01881 
01882   fclose(fp);
01883   
01884   *start  = GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(cert)),0);
01885   *finish = GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(cert)),0);
01886 
01887   X509_free(cert);
01888   
01889   return GRST_RET_OK;
01890 }
01891 
01892 /// Create a stack of X509 certificate from a PEM-encoded string
01893 int GRSTx509StringToChain(STACK_OF(X509) **certstack, char *certstring)
01894 ///
01895 /// Creates a dynamically allocated stack of X509 certificate objects
01896 /// by walking through the PEM-encoded X509 certificates.
01897 ///
01898 /// Returns GRST_RET_OK on success, non-zero otherwise.
01899 {   
01900   STACK_OF(X509_INFO) *sk=NULL;
01901   BIO *certbio;
01902   X509_INFO *xi;
01903 
01904   *certstack = sk_X509_new_null();
01905   if (*certstack == NULL) return GRST_RET_FAILED;
01906 
01907   certbio = BIO_new_mem_buf(certstring, -1);
01908   
01909   if (!(sk=PEM_X509_INFO_read_bio(certbio, NULL, NULL, NULL)))
01910     {
01911       BIO_free(certbio);
01912       sk_X509_INFO_free(sk);
01913       sk_X509_free(*certstack);
01914       return GRST_RET_FAILED;
01915     }
01916       
01917   while (sk_X509_INFO_num(sk))
01918        {
01919          xi=sk_X509_INFO_shift(sk);
01920          if (xi->x509 != NULL)
01921            {
01922              sk_X509_push(*certstack, xi->x509);
01923              xi->x509=NULL;
01924            }
01925          X509_INFO_free(xi);
01926        }
01927        
01928    if (!sk_X509_num(*certstack))
01929      {
01930        BIO_free(certbio);
01931        sk_X509_INFO_free(sk);
01932        sk_X509_free(*certstack);
01933        return GRST_RET_FAILED;
01934      }
01935 
01936    BIO_free(certbio);
01937    sk_X509_INFO_free(sk);
01938    
01939    return GRST_RET_OK;
01940 }
01941 
01942 /// Returns a Delegation ID based on hash of GRST_CRED_0, ...
01943 char *GRSTx509MakeDelegationID(void)
01944 ///
01945 /// Returns a malloc'd string with Delegation ID made by SHA1-hashing the
01946 /// values of the compact credentials exported by mod_gridsite
01947 { 
01948   unsigned char hash_delegation_id[EVP_MAX_MD_SIZE];        
01949   int  i;
01950   unsigned int delegation_id_len;
01951   char cred_name[14], *cred_value, *delegation_id;
01952   const EVP_MD *m;
01953   EVP_MD_CTX ctx;
01954 
01955   OpenSSL_add_all_digests();
01956 
01957   m = EVP_sha1();
01958   if (m == NULL) return NULL;
01959 
01960   EVP_DigestInit(&ctx, m);
01961 
01962   for (i=0; i <= 999; ++i)
01963      {
01964        snprintf(cred_name, sizeof(cred_name), "GRST_CRED_%d", i);       
01965        if ((cred_value = getenv(cred_name)) == NULL) break;
01966        
01967        EVP_DigestUpdate(&ctx, cred_value, strlen(cred_value));
01968      }
01969      
01970   EVP_DigestFinal(&ctx, hash_delegation_id, &delegation_id_len);
01971 
01972   delegation_id = malloc(17);
01973 
01974   for (i=0; i <=7; ++i)
01975    sprintf(&delegation_id[i*2], "%02x", hash_delegation_id[i]);
01976 
01977   delegation_id[16] = '\0';
01978 
01979   return delegation_id;
01980 }
01981 
01982 #if 0
01983 /// Return the short file name for the given delegation_id and user_dn
01984 char *GRSTx509MakeProxyFileName(char *delegation_id,
01985                                 STACK_OF(X509) *certstack)
01986 ///
01987 /// Returns a malloc'd string with the short file name (no paths) that
01988 /// derived from the hashed delegation_id and user_dn
01989 ///
01990 /// File name is SHA1_HASH(DelegationID)+"-"+SHA1_HASH(DN) where DN
01991 /// is DER encoded version of user_dn with any trailing CN=proxy removed
01992 /// Hashes are the most significant 8 bytes, in lowercase hexadecimal.
01993 { 
01994   int        i, depth, prevIsCA = 1, IsCA, hash_name_len, delegation_id_len,
01995                  der_name_len;
01996   unsigned char *der_name, *buf, hash_name[EVP_MAX_MD_SIZE],
01997                  hash_delegation_id[EVP_MAX_MD_SIZE],
01998                  filename[34];
01999   X509_NAME *subject_name;
02000   X509      *cert;
02001   const EVP_MD *m;
02002   EVP_MD_CTX ctx;
02003 
02004   depth = sk_X509_num(certstack);  
02005   
02006   for (i=depth-1; i >= 0; --i)
02007         /* loop through the proxy chain starting at CA end */
02008      {
02009        if (cert = sk_X509_value(certstack, i))
02010          {
02011            IsCA = (GRSTx509IsCA(cert) == GRST_RET_OK);
02012 
02013            if (prevIsCA && !IsCA) /* the full certificate of the user */
02014              {
02015                break;
02016              }
02017          }
02018      }
02019 
02020   if (i < 0) return NULL; /* not found: something wrong with the chain */
02021 
02022   if ((subject_name = X509_get_subject_name(cert)) == NULL) return NULL;
02023   
02024   der_name_len = i2d_X509_NAME(X509_get_subject_name(cert), NULL);
02025   if (der_name_len == 0) return NULL;
02026   
02027   buf = OPENSSL_malloc(der_name_len);
02028   der_name = buf;
02029 
02030 
02031   if (!i2d_X509_NAME(X509_get_subject_name(cert), &der_name))
02032     {
02033       OPENSSL_free(der_name);
02034       return NULL;
02035     }
02036 
02037   OpenSSL_add_all_digests();
02038 
02039   m = EVP_sha1();
02040   if (m == NULL)
02041     {
02042       OPENSSL_free(der_name);
02043       return NULL;
02044     }
02045 
02046 
02047   EVP_DigestInit(&ctx, m);
02048   EVP_DigestUpdate(&ctx, delegation_id, strlen(delegation_id));
02049   EVP_DigestFinal(&ctx, hash_delegation_id, &delegation_id_len);
02050 
02051   /* lots of nasty hard coded numbers: 
02052      "8bytes/16chars delegation ID" + "-" + "8bytes/16chars DN" */
02053 
02054   for (i=0; i <=7; ++i)
02055    sprintf(&filename[i*2], "%02x", hash_delegation_id[i]);
02056 
02057   filename[16] = '-';
02058 
02059   EVP_DigestInit(&ctx, m);
02060   EVP_DigestUpdate(&ctx, buf, der_name_len);
02061   EVP_DigestFinal(&ctx, hash_name, &hash_name_len);
02062 
02063   for (i=0; i <=7; ++i)
02064    sprintf(&filename[17 + i*2], "%02x", hash_name[i]);
02065 
02066   return strdup(filename);
02067 }
02068 #endif
02069 
02070 /// Store a GSI proxy chain in the proxy cache, along with the private key
02071 int GRSTx509CacheProxy(char *proxydir, char *delegation_id, 
02072                                        char *user_dn, char *proxychain)
02073 ///
02074 /// Returns GRST_RET_OK on success, non-zero otherwise. The existing
02075 /// private key with the same delegation ID and user DN is moved out of
02076 /// the temporary cache.
02077 {
02078   int   c, i;
02079   char *user_dn_enc, *ptr, *prvkeyfile, proxyfile[16384];
02080   STACK_OF(X509) *certstack;
02081   BIO  *certmem;
02082   X509 *cert;
02083   long  ptrlen;        
02084   FILE *ifp, *ofp;
02085 
02086   if (strcmp(user_dn, "cache") == 0) return GRST_RET_FAILED;
02087     
02088   /* find the existing private key file */
02089 
02090   prvkeyfile = GRSTx509CachedProxyKeyFind(proxydir, delegation_id, user_dn);
02091 
02092   if (prvkeyfile == NULL)
02093     {
02094       return GRST_RET_FAILED;
02095     }
02096 
02097   /* open it ready for later */
02098 
02099   if ((ifp = fopen(prvkeyfile, "r")) == NULL)
02100     {
02101       free(prvkeyfile);
02102       return GRST_RET_FAILED;
02103     }
02104 
02105   /* get the X509 stack */
02106 
02107   if (GRSTx509StringToChain(&certstack, proxychain) != GRST_RET_OK)
02108     {
02109       fclose(ifp);
02110       free(prvkeyfile);
02111       return GRST_RET_FAILED;
02112     }
02113 
02114   /* create directories if necessary, and set proxy filename */
02115 
02116   user_dn_enc = GRSThttpUrlEncode(user_dn);
02117 
02118   mkdir_printf(S_IRUSR | S_IWUSR | S_IXUSR, 
02119                "%s/%s",    proxydir, user_dn_enc);
02120   mkdir_printf(S_IRUSR | S_IWUSR | S_IXUSR, 
02121                "%s/%s/%s", proxydir, user_dn_enc, delegation_id);
02122 
02123   sprintf(proxyfile, "%s/%s/%s/userproxy.pem",
02124            proxydir, user_dn_enc, delegation_id);
02125            
02126   free(user_dn_enc);
02127 
02128   /* set up to write proxy file */
02129 
02130   ofp = fopen(proxyfile, "w");
02131   chmod(proxyfile, S_IRUSR | S_IWUSR);
02132 
02133   if (ofp == NULL)
02134     {
02135       fclose(ifp);
02136       free(prvkeyfile);
02137       return GRST_RET_FAILED;
02138     }
02139 
02140   /* write out the most recent proxy by itself */
02141 
02142   if ( (cert = sk_X509_value(certstack, 0)) )
02143     {
02144       certmem = BIO_new(BIO_s_mem());
02145       if (PEM_write_bio_X509(certmem, cert) == 1)
02146         {
02147           ptrlen = BIO_get_mem_data(certmem, &ptr);
02148           fwrite(ptr, 1, ptrlen, ofp);
02149         }
02150 
02151       BIO_free(certmem);
02152     }
02153 
02154   /* insert proxy private key, read from private key file */
02155 
02156   while ((c = fgetc(ifp)) != EOF) fputc(c, ofp);
02157   unlink(prvkeyfile);
02158   free(prvkeyfile);
02159 
02160   for (i=1; i <= sk_X509_num(certstack) - 1; ++i)
02161         /* loop through the proxy chain starting at 2nd most recent proxy */
02162      {
02163        if ( (cert = sk_X509_value(certstack, i)))
02164          {
02165            certmem = BIO_new(BIO_s_mem());
02166            if (PEM_write_bio_X509(certmem, cert) == 1)
02167              {
02168                ptrlen = BIO_get_mem_data(certmem, &ptr);
02169                fwrite(ptr, 1, ptrlen, ofp);
02170              }
02171 
02172            BIO_free(certmem);
02173          }
02174      }
02175 
02176   sk_X509_free(certstack);
02177 
02178   if (fclose(ifp) != 0) return GRST_RET_FAILED;
02179   if (fclose(ofp) != 0) return GRST_RET_FAILED;
02180 
02181   return GRST_RET_OK;
02182 }

Generated on Tue Jul 5 14:47:01 2011 for ROOT_528-00b_version by  doxygen 1.5.1