Changeset 9d9b093 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Jan 11, 2013, 12:56:51 AM (8 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
Branches:
debian/master, debian/stretch-backports, jessie-backports, upstream
Children:
2dd044f, 8ce897a
Parents:
8df5b25
Message:

Imported Upstream version 0.5.1

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r8df5b25 r9d9b093  
    3737static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    3838/* use side==0 for server and side==1 for client */
    39 static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert,
     39static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert,
     40                                     int side,
     41                                     int export_certificates_enabled);
     42static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert,
    4043                                     int side,
    4144                                     int export_certificates_enabled);
     
    6972#endif
    7073
     74    if (gnutls_check_version(LIBGNUTLS_VERSION)==NULL) {
     75        fprintf(stderr, "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n",
     76          LIBGNUTLS_VERSION, gnutls_check_version(NULL));
     77        return -3;
     78    }
     79
    7180    ret = gnutls_global_init();
    72     if (ret < 0) /* FIXME: can we print here? */
    73         exit(ret);
     81    if (ret < 0) {
     82        fprintf(stderr, "gnutls_global_init: %s\n", gnutls_strerror(ret));
     83        return -3;
     84    }
     85
     86    ret = gnutls_global_init_extra();
     87    if (ret < 0) {
     88        fprintf(stderr, "gnutls_global_init_extra: %s\n", gnutls_strerror(ret));
     89        return -3;
     90    }
    7491                                           
    7592    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
     
    83100    gnutls_global_set_log_level(9);
    84101    gnutls_global_set_log_function(gnutls_debug_log_all);
     102    apr_file_printf(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
    85103#endif
    86104
    87105    return OK;
    88106}
    89 
    90 /* We don't support openpgp certificates, yet */
    91 const static int cert_type_prio[2] = { GNUTLS_CRT_X509, 0 };
    92107
    93108static int mgs_select_virtual_server_cb(gnutls_session_t session)
     
    96111    mgs_srvconf_rec *tsc;
    97112    int ret;
     113    int cprio[2];
    98114
    99115    ctxt = gnutls_transport_get_ptr(session);
     
    129145     */
    130146    ret = gnutls_priority_set(session, ctxt->sc->priorities);
    131     gnutls_certificate_type_set_priority(session, cert_type_prio);
    132 
    133 
    134147    /* actually it shouldn't fail since we have checked at startup */
    135148    if (ret < 0)
    136149        return ret;
    137150
     151    /* If both certificate types are not present disallow them from
     152     * being negotiated.
     153     */
     154    if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) {
     155        cprio[0] = GNUTLS_CRT_X509;
     156        cprio[1] = 0;
     157        gnutls_certificate_type_set_priority( session, cprio);
     158    } else if (ctxt->sc->cert_pgp != NULL && ctxt->sc->certs_x509[0]==NULL) {
     159        cprio[0] = GNUTLS_CRT_OPENPGP;
     160        cprio[1] = 0;
     161        gnutls_certificate_type_set_priority( session, cprio);
     162    }
    138163
    139164    return 0;
     
    146171    ctxt = gnutls_transport_get_ptr(session);
    147172
    148     ret->type = GNUTLS_CRT_X509;
    149     ret->ncerts = ctxt->sc->certs_x509_num;
    150     ret->deinit_all = 0;
    151 
    152     ret->cert.x509 = ctxt->sc->certs_x509;
    153     ret->key.x509 = ctxt->sc->privkey_x509;
    154     return 0;
    155 }
    156 
     173    if (gnutls_certificate_type_get( session) == GNUTLS_CRT_X509) {
     174        ret->type = GNUTLS_CRT_X509;
     175        ret->ncerts = ctxt->sc->certs_x509_num;
     176        ret->deinit_all = 0;
     177
     178        ret->cert.x509 = ctxt->sc->certs_x509;
     179        ret->key.x509 = ctxt->sc->privkey_x509;
     180       
     181        return 0;
     182    } else if (gnutls_certificate_type_get( session) == GNUTLS_CRT_OPENPGP) {
     183        ret->type = GNUTLS_CRT_OPENPGP;
     184        ret->ncerts = 1;
     185        ret->deinit_all = 0;
     186
     187        ret->cert.pgp = ctxt->sc->cert_pgp;
     188        ret->key.pgp = ctxt->sc->privkey_pgp;
     189
     190        return 0;
     191   
     192    }
     193
     194    return GNUTLS_E_INTERNAL_ERROR;
     195}
     196
     197/* 2048-bit group parameters from SRP specification */
    157198const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
    158199    "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
     
    170211 */
    171212static int read_crt_cn(server_rec * s, apr_pool_t * p,
    172                        gnutls_x509_crt cert, char **cert_cn)
     213                       gnutls_x509_crt_t cert, char **cert_cn)
    173214{
    174215    int rv = 0, i;
     
    178219    *cert_cn = NULL;
    179220
     221    data_len = 0;
    180222    rv = gnutls_x509_crt_get_dn_by_oid(cert,
    181223                                       GNUTLS_OID_X520_COMMON_NAME,
     
    188230                                           0, *cert_cn, &data_len);
    189231    } else {                    /* No CN return subject alternative name */
    190         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    191                      "No common name found in certificate for '%s:%d'. Looking for subject alternative name.",
     232        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     233                     "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    192234                     s->server_hostname, s->port);
    193235        rv = 0;
     
    217259
    218260    return rv;
    219 
    220 }
     261}
     262
     263static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
     264                       gnutls_openpgp_crt_t cert, char **cert_cn)
     265{
     266    int rv = 0;
     267    size_t data_len;
     268
     269
     270    *cert_cn = NULL;
     271
     272    data_len = 0;
     273    rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
     274
     275    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
     276        *cert_cn = apr_palloc(p, data_len);
     277        rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, &data_len);
     278    } else {                    /* No CN return subject alternative name */
     279        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     280                     "No name found in PGP certificate for '%s:%d'.",
     281                     s->server_hostname, s->port);
     282    }
     283
     284    return rv;
     285}
     286
    221287
    222288int
     
    355421            if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    356422                rv = read_crt_cn(s, p, sc->certs_x509[0], &sc->cert_cn);
     423                if (rv < 0 && sc->cert_pgp != NULL)  /* try openpgp certificate */
     424                    rv = read_pgpcrt_cn(s, p, sc->cert_pgp, &sc->cert_cn);
     425
    357426                if (rv < 0) {
    358427                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
     
    483552    ctxt = gnutls_transport_get_ptr(session);
    484553
    485     sni_type = gnutls_certificate_type_get(session);
    486     if (sni_type != GNUTLS_CRT_X509) {
    487         /* In theory, we could support OpenPGP Certificates. Theory != code. */
    488         ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
    489                      ctxt->c->base_server,
    490                      "GnuTLS: Only x509 Certificates are currently supported.");
    491         return NULL;
    492     }
    493 
    494554    rv = gnutls_server_name_get(ctxt->session, sni_name,
    495555                                &data_len, &sni_type, 0);
     
    691751    apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp));
    692752
    693     mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
     753    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
     754        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0,
     755                             ctxt->sc->export_certificates_enabled);
     756    else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
     757        mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0,
    694758                             ctxt->sc->export_certificates_enabled);
    695759
     
    753817#define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT")
    754818static void
    755 mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt cert, int side,
     819mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side,
    756820                         int export_certificates_enabled)
    757821{
     
    859923        }
    860924    }
    861 
    862 
    863 }
    864 
    865 
     925}
     926
     927static void
     928mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side,
     929                         int export_certificates_enabled)
     930{
     931    unsigned char sbuf[64];     /* buffer to hold serials */
     932    char buf[AP_IOBUFSIZE];
     933    const char *tmp;
     934    size_t len;
     935    int ret;
     936
     937    apr_table_t *env = r->subprocess_env;
     938
     939    if (export_certificates_enabled != 0) {
     940        char cert_buf[10 * 1024];
     941        len = sizeof(cert_buf);
     942
     943        if (gnutls_openpgp_crt_export
     944            (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0)
     945            apr_table_setn(env,
     946                           apr_pstrcat(r->pool, MGS_SIDE, "_CERT", NULL),
     947                           apr_pstrmemdup(r->pool, cert_buf, len));
     948
     949    }
     950
     951    len = sizeof(buf);
     952    gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
     953    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL),
     954                   apr_pstrmemdup(r->pool, buf, len));
     955
     956    len = sizeof(sbuf);
     957    gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
     958    tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
     959    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", NULL),
     960                   apr_pstrdup(r->pool, tmp));
     961
     962    ret = gnutls_openpgp_crt_get_version(cert);
     963    if (ret > 0)
     964        apr_table_setn(env,
     965                       apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", NULL),
     966                       apr_psprintf(r->pool, "%u", ret));
     967
     968    apr_table_setn(env,
     969       apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), "OPENPGP");
     970
     971    tmp =
     972        mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
     973                    (cert), buf, sizeof(buf));
     974    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL),
     975                   apr_pstrdup(r->pool, tmp));
     976
     977    tmp =
     978        mgs_time2sz(gnutls_openpgp_crt_get_creation_time
     979                    (cert), buf, sizeof(buf));
     980    apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL),
     981                   apr_pstrdup(r->pool, tmp));
     982
     983    ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
     984    if (ret >= 0) {
     985        apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", NULL),
     986                       gnutls_pk_algorithm_get_name(ret));
     987    }
     988
     989}
     990
     991/* TODO: Allow client sending a X.509 certificate chain */
    866992static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt)
    867993{
     
    869995    unsigned int cert_list_size, status, expired;
    870996    int rv, ret;
    871     gnutls_x509_crt_t cert;
     997    union {
     998      gnutls_x509_crt_t x509;
     999      gnutls_openpgp_crt_t pgp;
     1000    } cert;
    8721001    apr_time_t activation_time, expiration_time, cur_time;
    8731002
     
    8951024    }
    8961025
    897     gnutls_x509_crt_init(&cert);
    898     rv = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
     1026    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
     1027        gnutls_x509_crt_init(&cert.x509);
     1028        rv = gnutls_x509_crt_import(cert.x509, &cert_list[0], GNUTLS_X509_FMT_DER);
     1029    } else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP) {
     1030        gnutls_openpgp_crt_init(&cert.pgp);
     1031        rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], GNUTLS_OPENPGP_FMT_RAW);
     1032    } else return HTTP_FORBIDDEN;
     1033 
    8991034    if (rv < 0) {
    900         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
     1035       ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    9011036                      "GnuTLS: Failed to Verify Peer: "
    9021037                      "Failed to import peer certificates.");
    903         ret = HTTP_FORBIDDEN;
    904         goto exit;
    905     }
    906 
    907     apr_time_ansi_put(&expiration_time,
    908                       gnutls_x509_crt_get_expiration_time(cert));
    909     apr_time_ansi_put(&activation_time,
    910                       gnutls_x509_crt_get_activation_time(cert));
    911 
    912     rv = gnutls_x509_crt_verify(cert, ctxt->sc->ca_list,
     1038       ret = HTTP_FORBIDDEN;
     1039       goto exit;
     1040    }
     1041
     1042    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509) {
     1043        apr_time_ansi_put(&expiration_time,
     1044                      gnutls_x509_crt_get_expiration_time(cert.x509));
     1045        apr_time_ansi_put(&activation_time,
     1046                      gnutls_x509_crt_get_activation_time(cert.x509));
     1047
     1048        rv = gnutls_x509_crt_verify(cert.x509, ctxt->sc->ca_list,
    9131049                                ctxt->sc->ca_list_size, 0, &status);
     1050    } else {
     1051        apr_time_ansi_put(&expiration_time,
     1052                      gnutls_openpgp_crt_get_expiration_time(cert.pgp));
     1053        apr_time_ansi_put(&activation_time,
     1054                      gnutls_openpgp_crt_get_creation_time(cert.pgp));
     1055
     1056        rv = gnutls_openpgp_crt_verify_ring(cert.pgp, ctxt->sc->pgp_list,
     1057                      0, &status);
     1058    }
    9141059
    9151060    if (rv < 0) {
     
    9171062                      "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
    9181063                      rv, gnutls_strerror(rv));
     1064        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
     1065            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
     1066                      "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
    9191067        ret = HTTP_FORBIDDEN;
    9201068        goto exit;
    9211069    }
     1070
     1071    /* TODO: X509 CRL Verification. */
     1072    /* May add later if anyone needs it.
     1073     */
     1074    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
    9221075
    9231076    expired = 0;
     
    9551108    }
    9561109
    957     /* TODO: Further Verification. */
    958     /* Revocation is X.509 non workable paradigm, I really doubt implementation
    959      * is worth doing --nmav
    960      */
    961 /// ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size);
    962 
    963 //    mgs_hook_fixups(r);
    964 //    rv = mgs_authz_lua(r);
    965 
    966     mgs_add_common_cert_vars(r, cert, 1,
     1110    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
     1111        mgs_add_common_cert_vars(r, cert.x509, 1,
     1112                             ctxt->sc->export_certificates_enabled);
     1113    else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
     1114        mgs_add_common_pgpcert_vars(r, cert.pgp, 1,
    9671115                             ctxt->sc->export_certificates_enabled);
    9681116
     
    9881136
    9891137  exit:
    990     gnutls_x509_crt_deinit(cert);
     1138    if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_X509)
     1139        gnutls_x509_crt_deinit(cert.x509);
     1140    else if (gnutls_certificate_type_get( ctxt->session) == GNUTLS_CRT_OPENPGP)
     1141        gnutls_openpgp_crt_deinit(cert.pgp);
    9911142    return ret;
    9921143
Note: See TracChangeset for help on using the changeset viewer.