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 / +554 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 *xrealloc(void *buf, size_t len)
748
{
749
    void *newp;
750
    if((newp = realloc(buf, len)) == NULL) {
751
        free(buf);
752
        return NULL;
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)
760
{
761
    char **new_ocsp_urls, *ocsp_url;
762
    int len, err = 0, new_nocsp_urls;
763
    if(*asn1 == ASN1_STRING) {
764
        len = *++asn1;
765
        asn1++;
766
        new_nocsp_urls = *nocsp_urls+1;
767
        if((new_ocsp_urls = realloc(*ocsp_urls,new_nocsp_urls)) == NULL) 
768
            err = 1;
769
        if(!err) {
770
            *ocsp_urls = new_ocsp_urls;
771
            *nocsp_urls = new_nocsp_urls;
772
            *(*ocsp_urls + *nocsp_urls) = NULL;
773
            if((ocsp_url = malloc((len+1)*sizeof(char))) == NULL)
774
                err = 1;
775
            else {
776
                memcpy(ocsp_url, asn1, len);
777
                *(ocsp_url+len) = '\0';
778
                *(*ocsp_urls + *nocsp_urls -1 ) = ocsp_url;
779
            }
780
        }
781
    }
782
    return err;
783
784
}
785
786
/* parses the ANS1 OID and if it is an OCSP OID then calls the parse_ocsp_url function */
787
static int parse_ASN1_OID(unsigned char *asn1, char ***ocsp_urls, int *nocsp_urls)
788
{
789
    int len, err = 0 ;
790
    const unsigned char OCSP_OID[] = {0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01};
791
792
    len = *++asn1;
793
    asn1++;
794
    if(memcmp(asn1, OCSP_OID, len) == 0 ) {
795
        asn1+=len;
796
        err = parse_ocsp_url(asn1, ocsp_urls, nocsp_urls);
797
    }
798
    return err;
799
}
800
801
802
/* Parses an ASN1 Sequence. It is a recursive function, since if it finds a  sequence
803
   within the sequence it calls recursively itself. This function stops when it finds 
804
   the end of the ASN1 sequence (marked by '\0'), so if there are other sequences within
805
   the same sequence the while loop parses the sequences */
806
807
/* This algo was developped with AIA in mind so it was tested only with this extension */
808
static int parse_ASN1_Sequence(unsigned char *asn1, char ***ocsp_urls, int *nocsp_urls)
809
{
810
    int len = 0 , err = 0;
811
    while( !err && *asn1 != '\0') {
812
        switch(*asn1) {
813
        case ASN1_SEQUENCE:
814
            len = *++asn1;
815
            asn1++;
816
            err = parse_ASN1_Sequence(asn1, ocsp_urls, nocsp_urls);
817
            break;
818
        case ASN1_OID:
819
            err = parse_ASN1_OID(asn1,ocsp_urls,nocsp_urls);
820
            return 0;
821
            break;
822
        default:
823
            err = 1; /* we shouldn't have any errors */
824
            break;
825
        }
826
        asn1+=len;
827
    }
828
    return err;
829
}
830
831
/* the main function that gets the ASN1 encoding string and returns
832
   a pointer to a NULL terminated "array" of char *, that contains
833
   the ocsp_urls */
834
static char **decode_OCSP_url(ASN1_OCTET_STRING *os)
835
{
836
    char **response = NULL;
837
    unsigned char *ocsp_urls;
838
    int i, len, err = 0, numofresponses = 0 ;
839
840
    len = ASN1_STRING_length(os);
841
842
    ocsp_urls = malloc((size_t)(len+1)*sizeof(char));
843
    memcpy(ocsp_urls,os->data, (size_t) len);
844
    ocsp_urls[len] = '\0';
845
846
    if ((response = malloc(sizeof(char *))) == NULL)
847
        return NULL;
848
    *response = NULL;
849
850
    err = parse_ASN1_Sequence(ocsp_urls, &response, &numofresponses);
851
    if (err) {
852
        for(i = 0 ; i < numofresponses ; i++)
853
            free(response[i]);
854
        free(response);
855
        response = NULL;
856
    }
857
858
    free(ocsp_urls);
859
    return response;
860
}
861
862
863
864
/* stolen from openssl ocsp command */
865
static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer,
866
  STACK_OF(OCSP_CERTID) *ids)
867
{
868
    OCSP_CERTID *id;
869
    if(!issuer)
870
        return 0;
871
    if(!*req) *req = OCSP_REQUEST_new();
872
    if(!*req) goto err;
873
    id = OCSP_cert_to_id(NULL, cert, issuer);
874
    if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err;
875
    if(!OCSP_request_add0_id(*req, id)) goto err;
876
    return 1;
877
878
err:
879
    return 0;
880
}
881
882
883
/* Creates the APR socket and connect to the hostname. Returns the 
884
   socket or NULL if there is an error.
885
*/
886
static apr_socket_t *make_socket(char *hostname, int port, apr_pool_t *mp)
887
{
888
    int r = 0;
889
    apr_sockaddr_t *sa_in;
890
    apr_status_t status;
891
    apr_socket_t *sock = NULL;
892
893
894
    status = apr_sockaddr_info_get(&sa_in, hostname, APR_INET, port, 0, mp);
895
896
    if(status == APR_SUCCESS)
897
        status = apr_socket_create(&sock, sa_in->family, SOCK_STREAM, APR_PROTO_TCP, mp);
898
    if(status == APR_SUCCESS)
899
        status = apr_socket_connect(sock, sa_in);
900
901
    if(status == APR_SUCCESS)
902
        return sock;
903
    return NULL;
904
905
}
906
907
908
/* Creates the request in a memory BIO in order to send it to the OCSP server.
909
   Most parts of this function are taken from mod_ssl support for OCSP (with some
910
   minor modifications
911
*/
912
static BIO *serialize_request(OCSP_REQUEST *req, char *host, int port, char *path)
913
{
914
    BIO *bio;
915
    int len;
916
917
    len = i2d_OCSP_REQUEST(req, NULL);
918
919
    bio = BIO_new(BIO_s_mem());
920
921
    BIO_printf(bio, "POST %s HTTP/1.0\r\n"
922
      "Host: %s:%d\r\n"
923
      "Content-Type: application/ocsp-request\r\n"
924
      "Content-Length: %d\r\n"
925
      "\r\n",
926
      path, host, port, len);
927
928
    if (i2d_OCSP_REQUEST_bio(bio, req) != 1) {
929
        BIO_free(bio);
930
        return NULL;
931
    }
932
933
    return bio;
934
}
935
936
937
/* Send the OCSP request to the OCSP server. Taken from mod_ssl OCSP support */
938
#define HUGE_STRING_LENGTH 8192
939
static int ocsp_send_req(apr_socket_t *sock, BIO *req)
940
{
941
    int len;
942
    char buf[HUGE_STRING_LENGTH];
943
    apr_status_t rv;
944
    int ok = 1;
945
946
    while ((len = BIO_read(req, buf, sizeof buf)) > 0) {
947
        char *wbuf = buf;
948
        apr_size_t remain = len;
949
950
        do {
951
            apr_size_t wlen = remain;
952
            rv = apr_socket_send(sock, wbuf, &wlen);
953
            wbuf += remain;
954
            remain -= wlen;
955
        } while (rv == APR_SUCCESS && remain > 0);
956
957
        if (rv != APR_SUCCESS) {
958
            apr_socket_close(sock);
959
            ok = 0;
960
        }
961
    }
962
963
    return ok;
964
}
965
966
967
968
/* Parses the buffer from the response and extracts the OCSP response.
969
   Taken from openssl library */
970
static OCSP_RESPONSE *parse_ocsp_resp(char *buf, int len)
971
{
972
    BIO *mem = NULL;
973
    char tmpbuf[1024];
974
    OCSP_RESPONSE *resp = NULL;
975
    char *p, *q, *r;
976
    int retcode;
977
978
    mem = BIO_new(BIO_s_mem());
979
    if(mem == NULL)
980
        return NULL;
981
982
    BIO_write(mem, buf, len);  /* write the buffer to the bio */
983
    if(BIO_gets(mem, tmpbuf, 512) <= 0) {
984
        OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
985
        goto err;
986
    }
987
    /* Parse the HTTP response. This will look like this:
988
     * "HTTP/1.0 200 OK". We need to obtain the numeric code and
989
     * (optional) informational message.
990
     */
991
992
    /* Skip to first white space (passed protocol info) */
993
    for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
994
    if(!*p) {
995
        goto err;
996
    }
997
    /* Skip past white space to start of response code */
998
    while(isspace((unsigned char)*p)) p++;
999
    if(!*p) {
1000
        goto err;
1001
    }
1002
    /* Find end of response code: first whitespace after start of code */
1003
    for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
1004
    if(!*q) {
1005
        goto err;
1006
    }
1007
    /* Set end of response code and start of message */
1008
    *q++ = 0;
1009
    /* Attempt to parse numeric code */
1010
    retcode = strtoul(p, &r, 10);
1011
    if(*r) goto err;
1012
    /* Skip over any leading white space in message */
1013
    while(isspace((unsigned char)*q))  q++;
1014
    if(*q) {
1015
        /* Finally zap any trailing white space in message (include CRLF) */
1016
        /* We know q has a non white space character so this is OK */
1017
        for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
1018
    }
1019
    if(retcode != 200) {
1020
        goto err;
1021
    }
1022
    /* Find blank line marking beginning of content */
1023
    while(BIO_gets(mem, tmpbuf, 512) > 0)
1024
    {
1025
        for(p = tmpbuf; isspace((unsigned char)*p); p++) continue;
1026
        if(!*p) break;
1027
    }
1028
    if(*p) {
1029
        goto err;
1030
    }
1031
    if(!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) {
1032
        goto err;
1033
    }
1034
err:
1035
    BIO_free(mem);
1036
    return resp;
1037
1038
1039
}
1040
1041
1042
/* Reads the respnse from the APR socket to a buffer, and parses the buffer to
1043
   return the OCSP response  */
1044
#define ADDLEN 512
1045
static OCSP_RESPONSE *ocsp_get_resp(apr_socket_t *sock)
1046
{
1047
    int buflen = 0, totalread = 0;
1048
    apr_size_t readlen;
1049
    char *buf, tmpbuf[ADDLEN];
1050
    apr_status_t rv = APR_SUCCESS;
1051
1052
    OCSP_RESPONSE *resp;
1053
1054
    buflen = ADDLEN;
1055
    buf = malloc(buflen);
1056
    if(buf == NULL)
1057
        return NULL;
1058
1059
    while(rv == APR_SUCCESS ) {
1060
        readlen = sizeof(tmpbuf);
1061
        rv = apr_socket_recv(sock, tmpbuf, &readlen);
1062
        if(rv == APR_SUCCESS) { /* if we have read something .. we can put it in the buffer*/
1063
            if((totalread + readlen) >= buflen) {
1064
                buflen+=ADDLEN; /* if needed we enlarge the buffer */
1065
                buf = xrealloc(buf,buflen);
1066
                if (buf == NULL) {
1067
                    return NULL;
1068
                }
1069
            }
1070
            memcpy(buf+totalread, tmpbuf, readlen); /* the copy to the buffer */
1071
            totalread+=readlen; /* update the total bytes read */
1072
        }
1073
        else {
1074
            if (rv == APR_EOF && readlen == 0 )
1075
                ; /* EOF, normal situation */
1076
            else if ( readlen == 0 ) {
1077
                /* Not success, and readlen == 0 .. some error */
1078
                free(buf);
1079
                return NULL;
1080
            }
1081
        }
1082
    }
1083
1084
1085
    resp = parse_ocsp_resp(buf, buflen);
1086
1087
    free(buf);
1088
1089
    return resp;
1090
}
1091
1092
/* Creates and OCSP request and returns the OCSP_RESPONSE */
1093
static OCSP_RESPONSE *get_ocsp_response(X509 *cert, X509 *issuer, char *url)
1094
{
1095
    OCSP_RESPONSE *ocsp_resp = NULL;
1096
    OCSP_REQUEST *ocsp_req = NULL;
1097
    BIO *bio_req;
1098
    char *hostname, *path, *c_port;
1099
    int port, use_ssl;
1100
    STACK_OF(OCSP_CERTID) *ids = NULL;
1101
    int ok = 0;
1102
1103
    apr_socket_t *apr_sock=NULL;
1104
1105
    apr_pool_t *mp;
1106
1107
    apr_pool_create(&mp, NULL);
1108
1109
    ids = sk_OCSP_CERTID_new_null();
1110
1111
    /* problem parsing the URL */
1112
    if(OCSP_parse_url(url,&hostname, &c_port, &path, &use_ssl) == 0 ) {
1113
        sk_OCSP_CERTID_free(ids);
1114
        return NULL;
1115
    }
1116
1117
    /* Create the OCSP request */
1118
    if(sscanf(c_port, "%d", &port) != 1)
1119
        goto end;
1120
    ocsp_req = OCSP_REQUEST_new();
1121
    if(ocsp_req == NULL)
1122
        return NULL;
1123
    if(add_ocsp_cert(&ocsp_req,cert,issuer,ids) == 0 )
1124
        goto free_req;
1125
1126
    /* create the BIO with the request to send */
1127
    bio_req = serialize_request(ocsp_req, hostname, port, path);
1128
    if(bio_req == NULL) {
1129
        goto free_req;
1130
    }
1131
1132
    apr_sock = make_socket(hostname, port, mp);
1133
    if (apr_sock == NULL) {
1134
        ocsp_resp = NULL;
1135
        goto free_bio;
1136
    }
1137
1138
    ok = ocsp_send_req(apr_sock, bio_req);
1139
    if(ok)
1140
        ocsp_resp = ocsp_get_resp(apr_sock);
1141
1142
free_bio:
1143
    BIO_free(bio_req);
1144
1145
free_req:
1146
    if(apr_sock && ok) /* if ok == 0 we have already closed the socket */
1147
        apr_socket_close(apr_sock);
1148
1149
    apr_pool_destroy(mp);
1150
1151
    sk_OCSP_CERTID_free(ids);
1152
    OCSP_REQUEST_free(ocsp_req);
1153
1154
end:
1155
    return ocsp_resp;
1156
}
1157
1158
/* Process the OCSP_RESPONSE and returns the corresponding
1159
   answert according to the status.
1160
*/
1161
static int processOCSPResponse(OCSP_RESPONSE *ocsp_resp)
1162
{
1163
    int r, o = V_OCSP_CERTSTATUS_UNKNOWN, i;
1164
    OCSP_BASICRESP *bs;
1165
    OCSP_SINGLERESP *ss;
1166
1167
    r = OCSP_response_status(ocsp_resp);
1168
1169
    if(r != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
1170
        OCSP_RESPONSE_free(ocsp_resp);
1171
        return OCSP_STATUS_UNKNOWN;
1172
    }
1173
    bs = OCSP_response_get1_basic(ocsp_resp);
1174
1175
    ss = OCSP_resp_get0(bs,0); /* we know we have only 1 request */
1176
1177
    i = OCSP_single_get0_status(ss, NULL, NULL, NULL, NULL);
1178
    if ( i == V_OCSP_CERTSTATUS_GOOD )
1179
        o =  OCSP_STATUS_OK;
1180
    else if ( i == V_OCSP_CERTSTATUS_REVOKED )
1181
        o = OCSP_STATUS_REVOKED;
1182
    else if ( i == V_OCSP_CERTSTATUS_UNKNOWN)
1183
        o = OCSP_STATUS_UNKNOWN;
1184
1185
    /* we clean up */
1186
    OCSP_RESPONSE_free(ocsp_resp);
1187
1188
    return o;
1189
}
1190
1191
1192
int ocspRequest(X509 *cert, X509 *issuer)
1193
{
1194
    char **ocsp_urls = NULL;
1195
    int nid, i;
1196
    X509_EXTENSION *ext;
1197
    ASN1_OCTET_STRING *os;
1198
1199
    /* Get the proper extension */
1200
    nid = X509_get_ext_by_NID(cert,NID_info_access,-1);
1201
    if(nid >= 0 ) {
1202
        ext = X509_get_ext(cert,nid);
1203
        os = X509_EXTENSION_get_data(ext);
1204
1205
        ocsp_urls = decode_OCSP_url(os);
1206
    }
1207
1208
    /* if we find the extensions and we can parse it check 
1209
       the ocsp status. Otherwise, return OCSP_STATUS_UNKNOWN */
1210
    if(ocsp_urls != NULL) {
1211
        OCSP_RESPONSE *resp;
1212
        /* for the time being just check for the fist response .. a better
1213
           approach is to iterate for all the possible ocsp urls */
1214
        resp = get_ocsp_response(cert, issuer, ocsp_urls[0]);
1215
1216
        /* memory clean up */
1217
        for(i = 0 ; ocsp_urls[i] != NULL ; i++ )
1218
            free(ocsp_urls[i]);
1219
        free(ocsp_urls);
1220
        if(resp != NULL)
1221
            return processOCSPResponse(resp);
1222
    }
1223
    return OCSP_STATUS_UNKNOWN;
1224
}
1225
1226
#endif /* HAVE_SSL_OCSP */
1227
675
#endif
1228
#endif

Return to bug 45392