1 /* ocsp_ext.c */
   2 /* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
   3  * project. */
   4 
   5 /* History:
   6    This file was transfered to Richard Levitte from CertCo by Kathy
   7    Weinhold in mid-spring 2000 to be included in OpenSSL or released
   8    as a patch kit. */
   9 
  10 /* ====================================================================
  11  * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
  12  *
  13  * Redistribution and use in source and binary forms, with or without
  14  * modification, are permitted provided that the following conditions
  15  * are met:
  16  *
  17  * 1. Redistributions of source code must retain the above copyright
  18  *    notice, this list of conditions and the following disclaimer.
  19  *
  20  * 2. Redistributions in binary form must reproduce the above copyright
  21  *    notice, this list of conditions and the following disclaimer in
  22  *    the documentation and/or other materials provided with the
  23  *    distribution.
  24  *
  25  * 3. All advertising materials mentioning features or use of this
  26  *    software must display the following acknowledgment:
  27  *    "This product includes software developed by the OpenSSL Project
  28  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
  29  *
  30  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
  31  *    endorse or promote products derived from this software without
  32  *    prior written permission. For written permission, please contact
  33  *    openssl-core@openssl.org.
  34  *
  35  * 5. Products derived from this software may not be called "OpenSSL"
  36  *    nor may "OpenSSL" appear in their names without prior written
  37  *    permission of the OpenSSL Project.
  38  *
  39  * 6. Redistributions of any form whatsoever must retain the following
  40  *    acknowledgment:
  41  *    "This product includes software developed by the OpenSSL Project
  42  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
  43  *
  44  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  45  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  47  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
  48  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  49  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  50  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  51  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  53  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  54  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  55  * OF THE POSSIBILITY OF SUCH DAMAGE.
  56  * ====================================================================
  57  *
  58  * This product includes cryptographic software written by Eric Young
  59  * (eay@cryptsoft.com).  This product includes software written by Tim
  60  * Hudson (tjh@cryptsoft.com).
  61  *
  62  */
  63 
  64 #include <stdio.h>
  65 #include <cryptlib.h>
  66 #include <openssl/objects.h>
  67 #include <openssl/x509.h>
  68 #include <openssl/ocsp.h>
  69 #include <openssl/rand.h>
  70 #include <openssl/x509v3.h>
  71 
  72 /* Standard wrapper functions for extensions */
  73 
  74 /* OCSP request extensions */
  75 
  76 int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *x)
  77         {
  78         return(X509v3_get_ext_count(x->tbsRequest->requestExtensions));
  79         }
  80 
  81 int OCSP_REQUEST_get_ext_by_NID(OCSP_REQUEST *x, int nid, int lastpos)
  82         {
  83         return(X509v3_get_ext_by_NID(x->tbsRequest->requestExtensions,nid,lastpos));
  84         }
  85 
  86 int OCSP_REQUEST_get_ext_by_OBJ(OCSP_REQUEST *x, ASN1_OBJECT *obj, int lastpos)
  87         {
  88         return(X509v3_get_ext_by_OBJ(x->tbsRequest->requestExtensions,obj,lastpos));
  89         }
  90 
  91 int OCSP_REQUEST_get_ext_by_critical(OCSP_REQUEST *x, int crit, int lastpos)
  92         {
  93         return(X509v3_get_ext_by_critical(x->tbsRequest->requestExtensions,crit,lastpos));
  94         }
  95 
  96 X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *x, int loc)
  97         {
  98         return(X509v3_get_ext(x->tbsRequest->requestExtensions,loc));
  99         }
 100 
 101 X509_EXTENSION *OCSP_REQUEST_delete_ext(OCSP_REQUEST *x, int loc)
 102         {
 103         return(X509v3_delete_ext(x->tbsRequest->requestExtensions,loc));
 104         }
 105 
 106 void *OCSP_REQUEST_get1_ext_d2i(OCSP_REQUEST *x, int nid, int *crit, int *idx)
 107         {
 108         return X509V3_get_d2i(x->tbsRequest->requestExtensions, nid, crit, idx);
 109         }
 110 
 111 int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *x, int nid, void *value, int crit,
 112                                                         unsigned long flags)
 113         {
 114         return X509V3_add1_i2d(&x->tbsRequest->requestExtensions, nid, value, crit, flags);
 115         }
 116 
 117 int OCSP_REQUEST_add_ext(OCSP_REQUEST *x, X509_EXTENSION *ex, int loc)
 118         {
 119         return(X509v3_add_ext(&(x->tbsRequest->requestExtensions),ex,loc) != NULL);
 120         }
 121 
 122 /* Single extensions */
 123 
 124 int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *x)
 125         {
 126         return(X509v3_get_ext_count(x->singleRequestExtensions));
 127         }
 128 
 129 int OCSP_ONEREQ_get_ext_by_NID(OCSP_ONEREQ *x, int nid, int lastpos)
 130         {
 131         return(X509v3_get_ext_by_NID(x->singleRequestExtensions,nid,lastpos));
 132         }
 133 
 134 int OCSP_ONEREQ_get_ext_by_OBJ(OCSP_ONEREQ *x, ASN1_OBJECT *obj, int lastpos)
 135         {
 136         return(X509v3_get_ext_by_OBJ(x->singleRequestExtensions,obj,lastpos));
 137         }
 138 
 139 int OCSP_ONEREQ_get_ext_by_critical(OCSP_ONEREQ *x, int crit, int lastpos)
 140         {
 141         return(X509v3_get_ext_by_critical(x->singleRequestExtensions,crit,lastpos));
 142         }
 143 
 144 X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *x, int loc)
 145         {
 146         return(X509v3_get_ext(x->singleRequestExtensions,loc));
 147         }
 148 
 149 X509_EXTENSION *OCSP_ONEREQ_delete_ext(OCSP_ONEREQ *x, int loc)
 150         {
 151         return(X509v3_delete_ext(x->singleRequestExtensions,loc));
 152         }
 153 
 154 void *OCSP_ONEREQ_get1_ext_d2i(OCSP_ONEREQ *x, int nid, int *crit, int *idx)
 155         {
 156         return X509V3_get_d2i(x->singleRequestExtensions, nid, crit, idx);
 157         }
 158 
 159 int OCSP_ONEREQ_add1_ext_i2d(OCSP_ONEREQ *x, int nid, void *value, int crit,
 160                                                         unsigned long flags)
 161         {
 162         return X509V3_add1_i2d(&x->singleRequestExtensions, nid, value, crit, flags);
 163         }
 164 
 165 int OCSP_ONEREQ_add_ext(OCSP_ONEREQ *x, X509_EXTENSION *ex, int loc)
 166         {
 167         return(X509v3_add_ext(&(x->singleRequestExtensions),ex,loc) != NULL);
 168         }
 169 
 170 /* OCSP Basic response */
 171 
 172 int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *x)
 173         {
 174         return(X509v3_get_ext_count(x->tbsResponseData->responseExtensions));
 175         }
 176 
 177 int OCSP_BASICRESP_get_ext_by_NID(OCSP_BASICRESP *x, int nid, int lastpos)
 178         {
 179         return(X509v3_get_ext_by_NID(x->tbsResponseData->responseExtensions,nid,lastpos));
 180         }
 181 
 182 int OCSP_BASICRESP_get_ext_by_OBJ(OCSP_BASICRESP *x, ASN1_OBJECT *obj, int lastpos)
 183         {
 184         return(X509v3_get_ext_by_OBJ(x->tbsResponseData->responseExtensions,obj,lastpos));
 185         }
 186 
 187 int OCSP_BASICRESP_get_ext_by_critical(OCSP_BASICRESP *x, int crit, int lastpos)
 188         {
 189         return(X509v3_get_ext_by_critical(x->tbsResponseData->responseExtensions,crit,lastpos));
 190         }
 191 
 192 X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *x, int loc)
 193         {
 194         return(X509v3_get_ext(x->tbsResponseData->responseExtensions,loc));
 195         }
 196 
 197 X509_EXTENSION *OCSP_BASICRESP_delete_ext(OCSP_BASICRESP *x, int loc)
 198         {
 199         return(X509v3_delete_ext(x->tbsResponseData->responseExtensions,loc));
 200         }
 201 
 202 void *OCSP_BASICRESP_get1_ext_d2i(OCSP_BASICRESP *x, int nid, int *crit, int *idx)
 203         {
 204         return X509V3_get_d2i(x->tbsResponseData->responseExtensions, nid, crit, idx);
 205         }
 206 
 207 int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *x, int nid, void *value, int crit,
 208                                                         unsigned long flags)
 209         {
 210         return X509V3_add1_i2d(&x->tbsResponseData->responseExtensions, nid, value, crit, flags);
 211         }
 212 
 213 int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *x, X509_EXTENSION *ex, int loc)
 214         {
 215         return(X509v3_add_ext(&(x->tbsResponseData->responseExtensions),ex,loc) != NULL);
 216         }
 217 
 218 /* OCSP single response extensions */
 219 
 220 int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *x)
 221         {
 222         return(X509v3_get_ext_count(x->singleExtensions));
 223         }
 224 
 225 int OCSP_SINGLERESP_get_ext_by_NID(OCSP_SINGLERESP *x, int nid, int lastpos)
 226         {
 227         return(X509v3_get_ext_by_NID(x->singleExtensions,nid,lastpos));
 228         }
 229 
 230 int OCSP_SINGLERESP_get_ext_by_OBJ(OCSP_SINGLERESP *x, ASN1_OBJECT *obj, int lastpos)
 231         {
 232         return(X509v3_get_ext_by_OBJ(x->singleExtensions,obj,lastpos));
 233         }
 234 
 235 int OCSP_SINGLERESP_get_ext_by_critical(OCSP_SINGLERESP *x, int crit, int lastpos)
 236         {
 237         return(X509v3_get_ext_by_critical(x->singleExtensions,crit,lastpos));
 238         }
 239 
 240 X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *x, int loc)
 241         {
 242         return(X509v3_get_ext(x->singleExtensions,loc));
 243         }
 244 
 245 X509_EXTENSION *OCSP_SINGLERESP_delete_ext(OCSP_SINGLERESP *x, int loc)
 246         {
 247         return(X509v3_delete_ext(x->singleExtensions,loc));
 248         }
 249 
 250 void *OCSP_SINGLERESP_get1_ext_d2i(OCSP_SINGLERESP *x, int nid, int *crit, int *idx)
 251         {
 252         return X509V3_get_d2i(x->singleExtensions, nid, crit, idx);
 253         }
 254 
 255 int OCSP_SINGLERESP_add1_ext_i2d(OCSP_SINGLERESP *x, int nid, void *value, int crit,
 256                                                         unsigned long flags)
 257         {
 258         return X509V3_add1_i2d(&x->singleExtensions, nid, value, crit, flags);
 259         }
 260 
 261 int OCSP_SINGLERESP_add_ext(OCSP_SINGLERESP *x, X509_EXTENSION *ex, int loc)
 262         {
 263         return(X509v3_add_ext(&(x->singleExtensions),ex,loc) != NULL);
 264         }
 265 
 266 /* also CRL Entry Extensions */
 267 #if 0
 268 ASN1_STRING *ASN1_STRING_encode(ASN1_STRING *s, i2d_of_void *i2d,
 269                                 void *data, STACK_OF(ASN1_OBJECT) *sk)
 270         {
 271         int i;
 272         unsigned char *p, *b = NULL;
 273 
 274         if (data)
 275                 {
 276                 if ((i=i2d(data,NULL)) <= 0) goto err;
 277                 if (!(b=p=OPENSSL_malloc((unsigned int)i)))
 278                         goto err;
 279                 if (i2d(data, &p) <= 0) goto err;
 280                 }
 281         else if (sk)
 282                 {
 283                 if ((i=i2d_ASN1_SET_OF_ASN1_OBJECT(sk,NULL,
 284                                                    (I2D_OF(ASN1_OBJECT))i2d,
 285                                                    V_ASN1_SEQUENCE,
 286                                                    V_ASN1_UNIVERSAL,
 287                                                    IS_SEQUENCE))<=0) goto err;
 288                 if (!(b=p=OPENSSL_malloc((unsigned int)i)))
 289                         goto err;
 290                 if (i2d_ASN1_SET_OF_ASN1_OBJECT(sk,&p,(I2D_OF(ASN1_OBJECT))i2d,
 291                                                 V_ASN1_SEQUENCE,
 292                                                 V_ASN1_UNIVERSAL,
 293                                                 IS_SEQUENCE)<=0) goto err;
 294                 }
 295         else
 296                 {
 297                 OCSPerr(OCSP_F_ASN1_STRING_ENCODE,OCSP_R_BAD_DATA);
 298                 goto err;
 299                 }
 300         if (!s && !(s = ASN1_STRING_new())) goto err;
 301         if (!(ASN1_STRING_set(s, b, i))) goto err;
 302         OPENSSL_free(b);
 303         return s;
 304 err:
 305         if (b) OPENSSL_free(b);
 306         return NULL;
 307         }
 308 #endif
 309 
 310 /* Nonce handling functions */
 311 
 312 /* Add a nonce to an extension stack. A nonce can be specificed or if NULL
 313  * a random nonce will be generated.
 314  * Note: OpenSSL 0.9.7d and later create an OCTET STRING containing the
 315  * nonce, previous versions used the raw nonce.
 316  */
 317 
 318 static int ocsp_add1_nonce(STACK_OF(X509_EXTENSION) **exts, unsigned char *val, int len)
 319         {
 320         unsigned char *tmpval;
 321         ASN1_OCTET_STRING os;
 322         int ret = 0;
 323         if (len <= 0) len = OCSP_DEFAULT_NONCE_LENGTH;
 324         /* Create the OCTET STRING manually by writing out the header and
 325          * appending the content octets. This avoids an extra memory allocation
 326          * operation in some cases. Applications should *NOT* do this because
 327          * it relies on library internals.
 328          */
 329         os.length = ASN1_object_size(0, len, V_ASN1_OCTET_STRING);
 330         os.data = OPENSSL_malloc(os.length);
 331         if (os.data == NULL)
 332                 goto err;
 333         tmpval = os.data;
 334         ASN1_put_object(&tmpval, 0, len, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL);
 335         if (val)
 336                 memcpy(tmpval, val, len);
 337         else
 338                 RAND_pseudo_bytes(tmpval, len);
 339         if(!X509V3_add1_i2d(exts, NID_id_pkix_OCSP_Nonce,
 340                         &os, 0, X509V3_ADD_REPLACE))
 341                                 goto err;
 342         ret = 1;
 343         err:
 344         if (os.data)
 345                 OPENSSL_free(os.data);
 346         return ret;
 347         }
 348 
 349 
 350 /* Add nonce to an OCSP request */
 351 
 352 int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len)
 353         {
 354         return ocsp_add1_nonce(&req->tbsRequest->requestExtensions, val, len);
 355         }
 356 
 357 /* Same as above but for a response */
 358 
 359 int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len)
 360         {
 361         return ocsp_add1_nonce(&resp->tbsResponseData->responseExtensions, val, len);
 362         }
 363 
 364 /* Check nonce validity in a request and response.
 365  * Return value reflects result:
 366  *  1: nonces present and equal.
 367  *  2: nonces both absent.
 368  *  3: nonce present in response only.
 369  *  0: nonces both present and not equal.
 370  * -1: nonce in request only.
 371  *
 372  *  For most responders clients can check return > 0.
 373  *  If responder doesn't handle nonces return != 0 may be
 374  *  necessary. return == 0 is always an error.
 375  */
 376 
 377 int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs)
 378         {
 379         /*
 380          * Since we are only interested in the presence or absence of
 381          * the nonce and comparing its value there is no need to use
 382          * the X509V3 routines: this way we can avoid them allocating an
 383          * ASN1_OCTET_STRING structure for the value which would be
 384          * freed immediately anyway.
 385          */
 386 
 387         int req_idx, resp_idx;
 388         X509_EXTENSION *req_ext, *resp_ext;
 389         req_idx = OCSP_REQUEST_get_ext_by_NID(req, NID_id_pkix_OCSP_Nonce, -1);
 390         resp_idx = OCSP_BASICRESP_get_ext_by_NID(bs, NID_id_pkix_OCSP_Nonce, -1);
 391         /* Check both absent */
 392         if((req_idx < 0) && (resp_idx < 0))
 393                 return 2;
 394         /* Check in request only */
 395         if((req_idx >= 0) && (resp_idx < 0))
 396                 return -1;
 397         /* Check in response but not request */
 398         if((req_idx < 0) && (resp_idx >= 0))
 399                 return 3;
 400         /* Otherwise nonce in request and response so retrieve the extensions */
 401         req_ext = OCSP_REQUEST_get_ext(req, req_idx);
 402         resp_ext = OCSP_BASICRESP_get_ext(bs, resp_idx);
 403         if(ASN1_OCTET_STRING_cmp(req_ext->value, resp_ext->value))
 404                 return 0;
 405         return 1;
 406         }
 407 
 408 /* Copy the nonce value (if any) from an OCSP request to
 409  * a response.
 410  */
 411 
 412 int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req)
 413         {
 414         X509_EXTENSION *req_ext;
 415         int req_idx;
 416         /* Check for nonce in request */
 417         req_idx = OCSP_REQUEST_get_ext_by_NID(req, NID_id_pkix_OCSP_Nonce, -1);
 418         /* If no nonce that's OK */
 419         if (req_idx < 0) return 2;
 420         req_ext = OCSP_REQUEST_get_ext(req, req_idx);
 421         return OCSP_BASICRESP_add_ext(resp, req_ext, -1);
 422         }
 423 
 424 X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim)
 425         {
 426         X509_EXTENSION *x = NULL;
 427         OCSP_CRLID *cid = NULL;
 428 
 429         if (!(cid = OCSP_CRLID_new())) goto err;
 430         if (url)
 431                 {
 432                 if (!(cid->crlUrl = ASN1_IA5STRING_new())) goto err;
 433                 if (!(ASN1_STRING_set(cid->crlUrl, url, -1))) goto err;
 434                 }
 435         if (n)
 436                 {
 437                 if (!(cid->crlNum = ASN1_INTEGER_new())) goto err;
 438                 if (!(ASN1_INTEGER_set(cid->crlNum, *n))) goto err;
 439                 }
 440         if (tim)
 441                 {
 442                 if (!(cid->crlTime = ASN1_GENERALIZEDTIME_new())) goto err;
 443                 if (!(ASN1_GENERALIZEDTIME_set_string(cid->crlTime, tim)))
 444                         goto err;
 445                 }
 446         x = X509V3_EXT_i2d(NID_id_pkix_OCSP_CrlID, 0, cid);
 447 err:
 448         if (cid) OCSP_CRLID_free(cid);
 449         return x;
 450         }
 451 
 452 /*   AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER */
 453 X509_EXTENSION *OCSP_accept_responses_new(char **oids)
 454         {
 455         int nid;
 456         STACK_OF(ASN1_OBJECT) *sk = NULL;
 457         ASN1_OBJECT *o = NULL;
 458         X509_EXTENSION *x = NULL;
 459 
 460         if (!(sk = sk_ASN1_OBJECT_new_null())) goto err;
 461         while (oids && *oids)
 462                 {
 463                 if ((nid=OBJ_txt2nid(*oids))!=NID_undef&&(o=OBJ_nid2obj(nid)))
 464                         sk_ASN1_OBJECT_push(sk, o);
 465                 oids++;
 466                 }
 467         x = X509V3_EXT_i2d(NID_id_pkix_OCSP_acceptableResponses, 0, sk);
 468 err:
 469         if (sk) sk_ASN1_OBJECT_pop_free(sk, ASN1_OBJECT_free);
 470         return x;
 471         }
 472 
 473 /*  ArchiveCutoff ::= GeneralizedTime */
 474 X509_EXTENSION *OCSP_archive_cutoff_new(char* tim)
 475         {
 476         X509_EXTENSION *x=NULL;
 477         ASN1_GENERALIZEDTIME *gt = NULL;
 478 
 479         if (!(gt = ASN1_GENERALIZEDTIME_new())) goto err;
 480         if (!(ASN1_GENERALIZEDTIME_set_string(gt, tim))) goto err;
 481         x = X509V3_EXT_i2d(NID_id_pkix_OCSP_archiveCutoff, 0, gt);
 482 err:
 483         if (gt) ASN1_GENERALIZEDTIME_free(gt);
 484         return x;
 485         }
 486 
 487 /* per ACCESS_DESCRIPTION parameter are oids, of which there are currently
 488  * two--NID_ad_ocsp, NID_id_ad_caIssuers--and GeneralName value.  This
 489  * method forces NID_ad_ocsp and uniformResourceLocator [6] IA5String.
 490  */
 491 X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME* issuer, char **urls)
 492         {
 493         X509_EXTENSION *x = NULL;
 494         ASN1_IA5STRING *ia5 = NULL;
 495         OCSP_SERVICELOC *sloc = NULL;
 496         ACCESS_DESCRIPTION *ad = NULL;
 497 
 498         if (!(sloc = OCSP_SERVICELOC_new())) goto err;
 499         if (!(sloc->issuer = X509_NAME_dup(issuer))) goto err;
 500         if (urls && *urls && !(sloc->locator = sk_ACCESS_DESCRIPTION_new_null())) goto err;
 501         while (urls && *urls)
 502                 {
 503                 if (!(ad = ACCESS_DESCRIPTION_new())) goto err;
 504                 if (!(ad->method=OBJ_nid2obj(NID_ad_OCSP))) goto err;
 505                 if (!(ad->location = GENERAL_NAME_new())) goto err;
 506                 if (!(ia5 = ASN1_IA5STRING_new())) goto err;
 507                 if (!ASN1_STRING_set((ASN1_STRING*)ia5, *urls, -1)) goto err;
 508                 ad->location->type = GEN_URI;
 509                 ad->location->d.ia5 = ia5;
 510                 if (!sk_ACCESS_DESCRIPTION_push(sloc->locator, ad)) goto err;
 511                 urls++;
 512                 }
 513         x = X509V3_EXT_i2d(NID_id_pkix_OCSP_serviceLocator, 0, sloc);
 514 err:
 515         if (sloc) OCSP_SERVICELOC_free(sloc);
 516         return x;
 517         }