View | Details | Raw Unified | Return to bug 45392
Collapse All | Expand All

(-)dfcd763ab174 (+22 lines)
Added Link Here
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#define OCSP_STATUS_OK        0
18
#define OCSP_STATUS_REVOKED   1
19
#define OCSP_STATUS_UNKNOWN   2
20
21
22
int ocspRequest(X509 *cert, X509 *issuer);
(-)a/jni/native/src/sslutils.c (-1 / +560 lines)
Lines 31-36 Link Here
31
extern int WIN32_SSL_password_prompt(tcn_pass_cb_t *data);
31
extern int WIN32_SSL_password_prompt(tcn_pass_cb_t *data);
32
#endif
32
#endif
33
33
34
#ifdef HAVE_SSL_OCSP
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <ctype.h>
39
40
#include <openssl/bio.h>
41
#include <openssl/ocsp.h>
42
43
#include "apr_network_io.h"
44
45
#include "ocsp_sock.h"
46
47
/* defines with the values as seen by the asn1parse -dump openssl command */
48
#define ASN1_SEQUENCE 0x30
49
#define ASN1_OID      0x06
50
#define ASN1_STRING   0x86
51
52
int ssl_verify_OCSP(int ok, X509_STORE_CTX *ctx);
53
54
#endif /* HAVE_SSL_OCSP */
34
/*  _________________________________________________________________
55
/*  _________________________________________________________________
35
**
56
**
36
**  Additional High-Level Functions for OpenSSL
57
**  Additional High-Level Functions for OpenSSL
Lines 621-626 Link Here
621
 * This OpenSSL callback function is called when OpenSSL
642
 * This OpenSSL callback function is called when OpenSSL
622
 * does client authentication and verifies the certificate chain.
643
 * does client authentication and verifies the certificate chain.
623
 */
644
 */
645
646
624
int SSL_callback_SSL_verify(int ok, X509_STORE_CTX *ctx)
647
int SSL_callback_SSL_verify(int ok, X509_STORE_CTX *ctx)
625
{
648
{
626
   /* Get Apache context back through OpenSSL context */
649
   /* Get Apache context back through OpenSSL context */
Lines 632-637 Link Here
632
    int errdepth = X509_STORE_CTX_get_error_depth(ctx);
655
    int errdepth = X509_STORE_CTX_get_error_depth(ctx);
633
    int verify   = con->ctx->verify_mode;
656
    int verify   = con->ctx->verify_mode;
634
    int depth    = con->ctx->verify_depth;
657
    int depth    = con->ctx->verify_depth;
658
    int ocsp_response;
659
    int skip_crl = 0;
635
660
636
    if (verify == SSL_CVERIFY_UNSET ||
661
    if (verify == SSL_CVERIFY_UNSET ||
637
        verify == SSL_CVERIFY_NONE)
662
        verify == SSL_CVERIFY_NONE)
Lines 642-651 Link Here
642
        ok = 1;
667
        ok = 1;
643
        SSL_set_verify_result(ssl, X509_V_OK);
668
        SSL_set_verify_result(ssl, X509_V_OK);
644
    }
669
    }
670
671
#ifdef HAVE_SSL_OCSP
672
    /* First perform OCSP validation if possible */
673
    if(ok) {
674
        ocsp_response = ssl_verify_OCSP(ok, ctx);
675
        if (ocsp_response == OCSP_STATUS_OK ) {
676
            skip_crl = 1; /* we know it is valid we skip crl evaluation */
677
        }
678
        else if(ocsp_response == OCSP_STATUS_REVOKED ) {
679
            ok = 0 ;
680
            errnum = X509_STORE_CTX_get_error(ctx);
681
        }
682
        else if (ocsp_response == OCSP_STATUS_UNKNOWN) 
683
            ; /* do nothing for time being, continue with CRL */
684
    }
685
#endif /* HAVE_SSL_OCSP */
645
    /*
686
    /*
646
     * Additionally perform CRL-based revocation checks
687
     * Additionally perform CRL-based revocation checks
647
     */
688
     */
648
    if (ok && con->ctx->crl) {
689
    if (ok && con->ctx->crl && !skip_crl) {
649
        if (!(ok = ssl_verify_CRL(ok, ctx, con))) {
690
        if (!(ok = ssl_verify_CRL(ok, ctx, con))) {
650
            errnum = X509_STORE_CTX_get_error(ctx);
691
            errnum = X509_STORE_CTX_get_error(ctx);
651
            /* TODO: Log something */
692
            /* TODO: Log something */
Lines 672-675 Link Here
672
    return ok;
713
    return ok;
673
}
714
}
674
715
716
#ifdef HAVE_SSL_OCSP
717
718
/* Function that is used to do the OCSP verification */
719
int ssl_verify_OCSP(int ok, X509_STORE_CTX *ctx)
720
{
721
    X509 *cert, *issuer;
722
    int r = OCSP_STATUS_UNKNOWN, o;
723
724
    cert = X509_STORE_CTX_get_current_cert(ctx);
725
726
    o = X509_STORE_CTX_get1_issuer(&issuer, ctx, cert);
727
    /* if we can't get the issuer, we cannot perform OCSP verification */
728
    if( o == 1 ) {
729
        r = ocspRequest(cert, issuer);
730
        if (r == OCSP_STATUS_REVOKED )
731
/* we set the error if we know that it is revoked */
732
            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
733
        else
734
            r = OCSP_STATUS_UNKNOWN; /* else we return unknown, so that we can continue with the crl */
735
        X509_free(issuer); /* It appears that we  should free issuer since
736
                              X509_STORE_CTX_get1_issuer() calls X509_OBJECT_up_ref_count()
737
                              on the issuer object (unline X509_STORE_CTX_get_current_cert()
738
                              that just returns the pointer */
739
740
    }
741
742
    return r;
743
}
744
745
746
/* Helps with error handling or realloc */
747
static void *apr_xrealloc(void *buf, size_t oldlen, size_t len, apr_pool_t *p)
748
{
749
    void *newp;
750
    newp = apr_palloc(p, len);
751
    if(newp)
752
            memcpy(newp, buf, oldlen);
753
754
    return newp;
755
}
756
757
/* parses the ocsp url and updates the ocsp_urls and nocsp_urls variables 
758
   returns 0 on success, 1 on failure */
759
static int parse_ocsp_url(unsigned char *asn1, char ***ocsp_urls, int *nocsp_urls, apr_pool_t *p)
760
{
761
    char **new_ocsp_urls, *ocsp_url;
762
    int len, err = 0, new_nocsp_urls;
763
764
    if(*asn1 == ASN1_STRING) {
765
        len = *++asn1;
766
        asn1++;
767
        new_nocsp_urls = *nocsp_urls+1;
768
        if((new_ocsp_urls = apr_xrealloc(*ocsp_urls,*nocsp_urls, new_nocsp_urls, p)) == NULL) 
769
            err = 1;
770
        if(!err) {
771
            *ocsp_urls = new_ocsp_urls;
772
            *nocsp_urls = new_nocsp_urls;
773
            *(*ocsp_urls + *nocsp_urls) = NULL;
774
            if((ocsp_url = apr_palloc(p, (len+1)*sizeof(char))) == NULL) {
775
                err = 1;
776
            }
777
            else {
778
                memcpy(ocsp_url, asn1, len);
779
                *(ocsp_url+len) = '\0';
780
                *(*ocsp_urls + *nocsp_urls -1 ) = ocsp_url;
781
            }
782
        }
783
    }
784
    return err;
785
786
}
787
788
/* parses the ANS1 OID and if it is an OCSP OID then calls the parse_ocsp_url function */
789
static int parse_ASN1_OID(unsigned char *asn1, char ***ocsp_urls, int *nocsp_urls, apr_pool_t *p)
790
{
791
    int len, err = 0 ;
792
    const unsigned char OCSP_OID[] = {0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01};
793
794
    len = *++asn1;
795
    asn1++;
796
    if(memcmp(asn1, OCSP_OID, len) == 0 ) {
797
        asn1+=len;
798
        err = parse_ocsp_url(asn1, ocsp_urls, nocsp_urls, p);
799
    }
800
    return err;
801
}
802
803
804
/* Parses an ASN1 Sequence. It is a recursive function, since if it finds a  sequence
805
   within the sequence it calls recursively itself. This function stops when it finds 
806
   the end of the ASN1 sequence (marked by '\0'), so if there are other sequences within
807
   the same sequence the while loop parses the sequences */
808
809
/* This algo was developped with AIA in mind so it was tested only with this extension */
810
static int parse_ASN1_Sequence(unsigned char *asn1, char ***ocsp_urls, int *nocsp_urls, apr_pool_t *p)
811
{
812
    int len = 0 , err = 0;
813
    while( !err && *asn1 != '\0') {
814
        switch(*asn1) {
815
        case ASN1_SEQUENCE:
816
            len = *++asn1;
817
            asn1++;
818
            err = parse_ASN1_Sequence(asn1, ocsp_urls, nocsp_urls, p);
819
            break;
820
        case ASN1_OID:
821
                err = parse_ASN1_OID(asn1,ocsp_urls,nocsp_urls, p);
822
            return 0;
823
            break;
824
        default:
825
            err = 1; /* we shouldn't have any errors */
826
            break;
827
        }
828
        asn1+=len;
829
    }
830
    return err;
831
}
832
833
/* the main function that gets the ASN1 encoding string and returns
834
   a pointer to a NULL terminated "array" of char *, that contains
835
   the ocsp_urls */
836
static char **decode_OCSP_url(ASN1_OCTET_STRING *os, apr_pool_t *p)
837
{
838
    char **response = NULL;
839
    unsigned char *ocsp_urls;
840
    int i, len, err = 0, numofresponses = 0 ;
841
842
    len = ASN1_STRING_length(os);
843
844
    ocsp_urls = apr_palloc(p, ((size_t)(len+1)*sizeof(char)));
845
    memcpy(ocsp_urls,os->data, (size_t) len);
846
    ocsp_urls[len] = '\0';
847
848
    if ((response = apr_palloc(p, sizeof(char *))) == NULL)
849
        return NULL;
850
    *response = NULL;
851
852
        err = parse_ASN1_Sequence(ocsp_urls, &response, &numofresponses, p);
853
    if (err) {
854
           response = NULL;
855
    }
856
857
   return response;
858
}
859
860
861
862
/* stolen from openssl ocsp command */
863
static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer,
864
  STACK_OF(OCSP_CERTID) *ids)
865
{
866
    OCSP_CERTID *id;
867
    if(!issuer)
868
        return 0;
869
    if(!*req) *req = OCSP_REQUEST_new();
870
    if(!*req) goto err;
871
    id = OCSP_cert_to_id(NULL, cert, issuer);
872
    if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err;
873
    if(!OCSP_request_add0_id(*req, id)) goto err;
874
    return 1;
875
876
err:
877
    return 0;
878
}
879
880
881
/* Creates the APR socket and connect to the hostname. Returns the 
882
   socket or NULL if there is an error.
883
*/
884
static apr_socket_t *make_socket(char *hostname, int port, apr_pool_t *mp)
885
{
886
    int r = 0;
887
    apr_sockaddr_t *sa_in;
888
    apr_status_t status;
889
    apr_socket_t *sock = NULL;
890
891
892
    status = apr_sockaddr_info_get(&sa_in, hostname, APR_INET, port, 0, mp);
893
894
    if(status == APR_SUCCESS)
895
        status = apr_socket_create(&sock, sa_in->family, SOCK_STREAM, APR_PROTO_TCP, mp);
896
    if(status == APR_SUCCESS)
897
        status = apr_socket_connect(sock, sa_in);
898
899
    if(status == APR_SUCCESS)
900
        return sock;
901
    return NULL;
902
903
}
904
905
906
/* Creates the request in a memory BIO in order to send it to the OCSP server.
907
   Most parts of this function are taken from mod_ssl support for OCSP (with some
908
   minor modifications
909
*/
910
static BIO *serialize_request(OCSP_REQUEST *req, char *host, int port, char *path)
911
{
912
    BIO *bio;
913
    int len;
914
915
    len = i2d_OCSP_REQUEST(req, NULL);
916
917
    bio = BIO_new(BIO_s_mem());
918
919
    BIO_printf(bio, "POST %s HTTP/1.0\r\n"
920
      "Host: %s:%d\r\n"
921
      "Content-Type: application/ocsp-request\r\n"
922
      "Content-Length: %d\r\n"
923
      "\r\n",
924
      path, host, port, len);
925
926
    if (i2d_OCSP_REQUEST_bio(bio, req) != 1) {
927
        BIO_free(bio);
928
        return NULL;
929
    }
930
931
    return bio;
932
}
933
934
935
/* Send the OCSP request to the OCSP server. Taken from mod_ssl OCSP support */
936
#define HUGE_STRING_LENGTH 8192
937
static int ocsp_send_req(apr_socket_t *sock, BIO *req)
938
{
939
    int len;
940
    char buf[HUGE_STRING_LENGTH];
941
    apr_status_t rv;
942
    int ok = 1;
943
944
    while ((len = BIO_read(req, buf, sizeof buf)) > 0) {
945
        char *wbuf = buf;
946
        apr_size_t remain = len;
947
948
        do {
949
            apr_size_t wlen = remain;
950
            rv = apr_socket_send(sock, wbuf, &wlen);
951
            wbuf += remain;
952
            remain -= wlen;
953
        } while (rv == APR_SUCCESS && remain > 0);
954
955
        if (rv != APR_SUCCESS) {
956
            apr_socket_close(sock);
957
            ok = 0;
958
        }
959
    }
960
961
    return ok;
962
}
963
964
965
966
/* Parses the buffer from the response and extracts the OCSP response.
967
   Taken from openssl library */
968
static OCSP_RESPONSE *parse_ocsp_resp(char *buf, int len)
969
{
970
    BIO *mem = NULL;
971
    char tmpbuf[1024];
972
    OCSP_RESPONSE *resp = NULL;
973
    char *p, *q, *r;
974
    int retcode;
975
976
    mem = BIO_new(BIO_s_mem());
977
    if(mem == NULL)
978
        return NULL;
979
980
    BIO_write(mem, buf, len);  /* write the buffer to the bio */
981
    if(BIO_gets(mem, tmpbuf, 512) <= 0) {
982
        OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
983
        goto err;
984
    }
985
    /* Parse the HTTP response. This will look like this:
986
     * "HTTP/1.0 200 OK". We need to obtain the numeric code and
987
     * (optional) informational message.
988
     */
989
990
    /* Skip to first white space (passed protocol info) */
991
    for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
992
    if(!*p) {
993
        goto err;
994
    }
995
    /* Skip past white space to start of response code */
996
    while(isspace((unsigned char)*p)) p++;
997
    if(!*p) {
998
        goto err;
999
    }
1000
    /* Find end of response code: first whitespace after start of code */
1001
    for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
1002
    if(!*q) {
1003
        goto err;
1004
    }
1005
    /* Set end of response code and start of message */
1006
    *q++ = 0;
1007
    /* Attempt to parse numeric code */
1008
    retcode = strtoul(p, &r, 10);
1009
    if(*r) goto err;
1010
    /* Skip over any leading white space in message */
1011
    while(isspace((unsigned char)*q))  q++;
1012
    if(*q) {
1013
        /* Finally zap any trailing white space in message (include CRLF) */
1014
        /* We know q has a non white space character so this is OK */
1015
        for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
1016
    }
1017
    if(retcode != 200) {
1018
        goto err;
1019
    }
1020
    /* Find blank line marking beginning of content */
1021
    while(BIO_gets(mem, tmpbuf, 512) > 0)
1022
    {
1023
        for(p = tmpbuf; isspace((unsigned char)*p); p++) continue;
1024
        if(!*p) break;
1025
    }
1026
    if(*p) {
1027
        goto err;
1028
    }
1029
    if(!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) {
1030
        goto err;
1031
    }
1032
err:
1033
    BIO_free(mem);
1034
    return resp;
1035
1036
1037
}
1038
1039
1040
/* Reads the respnse from the APR socket to a buffer, and parses the buffer to
1041
   return the OCSP response  */
1042
#define ADDLEN 512
1043
static OCSP_RESPONSE *ocsp_get_resp(apr_socket_t *sock)
1044
{
1045
    int buflen = 0, totalread = 0;
1046
    apr_size_t readlen;
1047
    char *buf, tmpbuf[ADDLEN];
1048
    apr_status_t rv = APR_SUCCESS;
1049
    apr_pool_t *p;
1050
1051
    OCSP_RESPONSE *resp;
1052
1053
    apr_pool_create(&p, NULL);
1054
1055
    buflen = ADDLEN;
1056
    buf = apr_palloc(p, buflen);
1057
    if(buf == NULL) {
1058
        apr_pool_destroy(p);
1059
        return NULL;
1060
    }
1061
1062
    while(rv == APR_SUCCESS ) {
1063
        readlen = sizeof(tmpbuf);
1064
        rv = apr_socket_recv(sock, tmpbuf, &readlen);
1065
        if(rv == APR_SUCCESS) { /* if we have read something .. we can put it in the buffer*/
1066
            if((totalread + readlen) >= buflen) {
1067
                buf = apr_xrealloc(buf,buflen,buflen+ADDLEN, p);
1068
                if (buf == NULL) {
1069
                    apr_pool_destroy(p);
1070
                    return NULL;
1071
                }
1072
                buflen+=ADDLEN; /* if needed we enlarge the buffer */
1073
            }
1074
            memcpy(buf+totalread, tmpbuf, readlen); /* the copy to the buffer */
1075
            totalread+=readlen; /* update the total bytes read */
1076
        }
1077
        else {
1078
            if (rv == APR_EOF && readlen == 0 )
1079
                ; /* EOF, normal situation */
1080
            else if ( readlen == 0 ) {
1081
                /* Not success, and readlen == 0 .. some error */
1082
                apr_pool_destroy(p);
1083
                return NULL;
1084
            }
1085
        }
1086
    }
1087
1088
1089
    resp = parse_ocsp_resp(buf, buflen);
1090
1091
    apr_pool_destroy(p);
1092
1093
    return resp;
1094
}
1095
1096
/* Creates and OCSP request and returns the OCSP_RESPONSE */
1097
static OCSP_RESPONSE *get_ocsp_response(X509 *cert, X509 *issuer, char *url)
1098
{
1099
    OCSP_RESPONSE *ocsp_resp = NULL;
1100
    OCSP_REQUEST *ocsp_req = NULL;
1101
    BIO *bio_req;
1102
    char *hostname, *path, *c_port;
1103
    int port, use_ssl;
1104
    STACK_OF(OCSP_CERTID) *ids = NULL;
1105
    int ok = 0;
1106
1107
    apr_socket_t *apr_sock=NULL;
1108
1109
    apr_pool_t *mp;
1110
1111
    apr_pool_create(&mp, NULL);
1112
1113
    ids = sk_OCSP_CERTID_new_null();
1114
1115
    /* problem parsing the URL */
1116
    if(OCSP_parse_url(url,&hostname, &c_port, &path, &use_ssl) == 0 ) {
1117
        sk_OCSP_CERTID_free(ids);
1118
        return NULL;
1119
    }
1120
1121
    /* Create the OCSP request */
1122
    if(sscanf(c_port, "%d", &port) != 1)
1123
        goto end;
1124
    ocsp_req = OCSP_REQUEST_new();
1125
    if(ocsp_req == NULL)
1126
        return NULL;
1127
    if(add_ocsp_cert(&ocsp_req,cert,issuer,ids) == 0 )
1128
        goto free_req;
1129
1130
    /* create the BIO with the request to send */
1131
    bio_req = serialize_request(ocsp_req, hostname, port, path);
1132
    if(bio_req == NULL) {
1133
        goto free_req;
1134
    }
1135
1136
    apr_sock = make_socket(hostname, port, mp);
1137
    if (apr_sock == NULL) {
1138
        ocsp_resp = NULL;
1139
        goto free_bio;
1140
    }
1141
1142
    ok = ocsp_send_req(apr_sock, bio_req);
1143
    if(ok)
1144
        ocsp_resp = ocsp_get_resp(apr_sock);
1145
1146
free_bio:
1147
    BIO_free(bio_req);
1148
1149
free_req:
1150
    if(apr_sock && ok) /* if ok == 0 we have already closed the socket */
1151
        apr_socket_close(apr_sock);
1152
1153
    apr_pool_destroy(mp);
1154
1155
    sk_OCSP_CERTID_free(ids);
1156
    OCSP_REQUEST_free(ocsp_req);
1157
1158
end:
1159
    return ocsp_resp;
1160
}
1161
1162
/* Process the OCSP_RESPONSE and returns the corresponding
1163
   answert according to the status.
1164
*/
1165
static int processOCSPResponse(OCSP_RESPONSE *ocsp_resp)
1166
{
1167
    int r, o = V_OCSP_CERTSTATUS_UNKNOWN, i;
1168
    OCSP_BASICRESP *bs;
1169
    OCSP_SINGLERESP *ss;
1170
1171
    r = OCSP_response_status(ocsp_resp);
1172
1173
    if(r != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
1174
        OCSP_RESPONSE_free(ocsp_resp);
1175
        return OCSP_STATUS_UNKNOWN;
1176
    }
1177
    bs = OCSP_response_get1_basic(ocsp_resp);
1178
1179
    ss = OCSP_resp_get0(bs,0); /* we know we have only 1 request */
1180
1181
    i = OCSP_single_get0_status(ss, NULL, NULL, NULL, NULL);
1182
    if ( i == V_OCSP_CERTSTATUS_GOOD )
1183
        o =  OCSP_STATUS_OK;
1184
    else if ( i == V_OCSP_CERTSTATUS_REVOKED )
1185
        o = OCSP_STATUS_REVOKED;
1186
    else if ( i == V_OCSP_CERTSTATUS_UNKNOWN)
1187
        o = OCSP_STATUS_UNKNOWN;
1188
1189
    /* we clean up */
1190
    OCSP_RESPONSE_free(ocsp_resp);
1191
1192
    return o;
1193
}
1194
1195
1196
int ocspRequest(X509 *cert, X509 *issuer)
1197
{
1198
    char **ocsp_urls = NULL;
1199
    int nid, i;
1200
    X509_EXTENSION *ext;
1201
    ASN1_OCTET_STRING *os;
1202
1203
    apr_pool_t *p;
1204
1205
    apr_pool_create(&p, NULL);
1206
1207
    /* Get the proper extension */
1208
    nid = X509_get_ext_by_NID(cert,NID_info_access,-1);
1209
    if(nid >= 0 ) {
1210
        ext = X509_get_ext(cert,nid);
1211
        os = X509_EXTENSION_get_data(ext);
1212
1213
        ocsp_urls = decode_OCSP_url(os, p);
1214
    }
1215
1216
    /* if we find the extensions and we can parse it check 
1217
       the ocsp status. Otherwise, return OCSP_STATUS_UNKNOWN */
1218
    if(ocsp_urls != NULL) {
1219
        OCSP_RESPONSE *resp;
1220
        /* for the time being just check for the fist response .. a better
1221
           approach is to iterate for all the possible ocsp urls */
1222
        resp = get_ocsp_response(cert, issuer, ocsp_urls[0]);
1223
1224
        apr_pool_destroy(p);
1225
        if(resp != NULL)
1226
            return processOCSPResponse(resp);
1227
    }
1228
    apr_pool_destroy(p);
1229
    return OCSP_STATUS_UNKNOWN;
1230
}
1231
1232
#endif /* HAVE_SSL_OCSP */
1233
675
#endif
1234
#endif

Return to bug 45392