You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modules-dev@httpd.apache.org by oh...@cox.net on 2012/06/17 21:46:11 UTC

How to access client certificate PEM and incoming request headers in a module?

Hi,

I am starting to look into implementing an Apache module that can use information from an incoming request, including several headers and the subject string from a client certificate to do authentication.

I've been looking at the source for mod_auth_certificate, from https://modules.apache.org/, as a starting point. 

However, it looks like the way that mod_auth_certificate works is that it requires that there's an SSLUserName directive to put the client certificate DN into the Apache REMOTE_USER attribute, whereas I need the entire PEM for the client cert to do authentication that I'm trying to do.

So I was wondering if it's possible for a module to access the SSL_CLIENT_S_DN and SSL_CLIENT_CERT environment variables, and if so, how?

Also, as mentioned my module would need to access several HTTP headers that are in the incoming requests.  How can it do that?

Thanks,
Jim



Re: How to access client certificate PEM and incoming request headers in a module?

Posted by oh...@cox.net.
Hi,

Also, I configured the Apache for client-authenticated SSL, and hit the https://<hostname>/test URL, and the dump_envvars() output only one additional variable:

In ap_headers_insert_output_filter: About to call dump_envvars...
In iterate_function: [UNIQUE_ID] => [T993fkjX4QkAAHanMQwAAAAA]
In iterate_function: [HTTPS] => [on]
In ap_headers_insert_output_filter: Returned from calling dump_envvars...

but not the other SSL-related variables, but if I add:

SSLOptions +FakeBasicAuth +ExportCertData +StdEnvVars

to the <VirtualHost> in extras/httpd-ssl.conf, WOOHOO(!), I get a bunch of SSL stuff :)...

In ap_headers_insert_output_filter: About to call dump_envvars...
In iterate_function: [UNIQUE_ID] => [T995GkjX4QkAAHdbMDwAAAAA]
In iterate_function: [HTTPS] => [on]
In iterate_function: [SSL_SERVER_S_DN_C] => [US]
In iterate_function: [SSL_SERVER_S_DN_ST] => [VA]
In iterate_function: [SSL_SERVER_S_DN_L] => [anywhere]
In iterate_function: [SSL_SERVER_S_DN_O] => [apache1OU]
In iterate_function: [SSL_SERVER_S_DN_OU] => [apache1O]
In iterate_function: [SSL_SERVER_S_DN_CN] => [apache1.whatever.com]
In iterate_function: [SSL_SERVER_S_DN_Email] => [apache1@whatever.com]
In iterate_function: [SSL_SERVER_I_DN_C] => [US]
In iterate_function: [SSL_SERVER_I_DN_ST] => [VA]
In iterate_function: [SSL_SERVER_I_DN_L] => [OAKTON]
.
.
In iterate_function: [SSL_CLIENT_CERT] => [-----BEGIN CERTIFICATE-----
MIICrTCCAhagAwIBAgICECUwDQYJKoZIhvcNAQEEBQAwgZMxCzAJBgNVBAYTAlVT
MQswCQYDVQQIEwJWQTEPMA0GA1UEBxMGT0FLVE9OMRMwEQYDVQQKEwpKTFNpbXBs
ZUNBMRIwEAYDVQQLEwlKTERlbW8gQ0ExGzAZBgNVBAMTEkpMU2ltcGxlQ0EgRGVt
.
.
.
bTAdBgNVHREEFjAUgRIwdGVzdEB3aGF0ZXZlci5jb20wDAYDVR0TAQH/BAIwADAf
BgNVHSMEGDAWgBTJ71+0oml+Oj7gfrPou0WoH9FdfDAdBgNVHSUEFjAUBggrBgEF
BQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEEBQADgYEAlg/aIr37XL+HsP2nqAeO
6VXByxwymKvUyYjQkAhp4OdywzXlqTmBUiEGHx07OevzyU3+y5E95+X6/QkPm4A6
Mvdk9B1tvcnvilz7iYUblDBHU1YNrvG7iu2XTxl723QWGUJcYgpE6ldHuRv+gz1d
RU3EW0UERzS/1UJAJ0QnGF4=
-----END CERTIFICATE-----
]
.
.


Jim

---- ohaya@cox.net wrote: 
> Hi,
> 
> I found some snippets that I used to make some dump_requests and dump_envvars functions:
> 
> /* START DUMP CODE
>  * Adapted from: http://thomas.eibner.dk/apache/table.html
>  */
> int iterate_func(void *req, const char *key, const char *value) {
>     int stat;
>     char *line;
>     request_rec *r = (request_rec *)req;
>     if (key == NULL || value == NULL || value[0] == '\0')
>         return 1;
>     
>     printf("In iterate_function: [%s] => [%s]\n", key, value);
>     //line = apr_psprintf(r->pool, "%s => %s\n", key, value);
>     //stat = ap_rputs(line, r);
> 
>     return 1;
> }
> 
> 
> 
> static int dump_request(request_rec *r) {
>     r->content_type = "text/plain";
>     //apr_send_http_header(r);
>     if (r->header_only)
>         return OK;
> 
>     apr_table_do(iterate_func, r, r->headers_in, NULL);
> 
>     return OK;
> }
> 
> 
> static int dump_envvars(request_rec *r) {
>     r->content_type = "text/plain";
>     //apr_send_http_header(r);
>     //if (r->header_only)
>     //    return OK;
> 
>     apr_table_do(iterate_func, r, r->subprocess_env, NULL);
> 
>     return OK;
> }
> 
> And I call them:
> 
>     printf("In ap_headers_insert_output_filter\n");
>     printf("In ap_headers_insert_output_filter: REQUEST_URI=[%s]\n", header_request_env_var(r, "REQUEST_URI") );
>     printf("In ap_headers_insert_output_filter: About to call dump_request...");
>     dump_request(r);
>     printf("In ap_headers_insert_output_filter: Returned from calling dump_request...\n");
>     printf("In ap_headers_insert_output_filter: About to call dump_envvars...");
>     dump_envvars(r);
>     printf("In ap_headers_insert_output_filter: Returned from calling dump_envvars...\n");
> 
> from inside the ap_headers_insert_output_filter() function in mod_headers (again, just an experiment).
> 
> The dump_request() does seem to return a bunch of the request headers, including one that I set using RequestHeader directive, but the dump_envvars() returned only one envvar, UNIQUE_ID.
> 
> Is that to be expected?  Is there somewhere else in the mod_headers.c code that I could put these dump_envvars() calls that would show more envvars?
> 
> Thanks,
> Jim
> 
> 
> ---- ohaya@cox.net wrote: 
> > Hi Sorin and Ben,
> > 
> > I found a list of variables somewhere, and just (probably unluckily) picked REMOTE_URI, just to see if retrieving any variable would work (an experiment).  Is there a list of environment variables that WOULD return something other than null for that call?
> > 
> > Thanks,
> > Jim
> > 
> > 
> > ---- Ben Noordhuis <in...@bnoordhuis.nl> wrote: 
> > > On Mon, Jun 18, 2012 at 8:53 AM,  <oh...@cox.net> wrote:
> > > > I added a call to header_request_env_var(r, "REMOTE_URI"), just to see what it got (running Apache in single-process mode):
> > > >
> > > > printf("REMOTE_URI=[%s]\n", header_request_env_var(r, "REMOTE_URI") );
> > > >
> > > > Then I pointed a browser to http://<myhost>/test, where /test was a <Location> with a RequestHeader (to trigger mod_headers) but I got:
> > > >
> > > > REMOTE_URI=[(null)]
> > > >
> > > > Shouldn't that be showing:
> > > >
> > > > REMOTE_URI=[/test]
> > > >
> > > > ??
> > > 
> > > Did you mean REMOTE_USER or REQUEST_URI? I don't think there's such a
> > > thing as REMOTE_URI.
> > 

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by oh...@cox.net.
Hi,

I found some snippets that I used to make some dump_requests and dump_envvars functions:

/* START DUMP CODE
 * Adapted from: http://thomas.eibner.dk/apache/table.html
 */
int iterate_func(void *req, const char *key, const char *value) {
    int stat;
    char *line;
    request_rec *r = (request_rec *)req;
    if (key == NULL || value == NULL || value[0] == '\0')
        return 1;
    
    printf("In iterate_function: [%s] => [%s]\n", key, value);
    //line = apr_psprintf(r->pool, "%s => %s\n", key, value);
    //stat = ap_rputs(line, r);

    return 1;
}



static int dump_request(request_rec *r) {
    r->content_type = "text/plain";
    //apr_send_http_header(r);
    if (r->header_only)
        return OK;

    apr_table_do(iterate_func, r, r->headers_in, NULL);

    return OK;
}


static int dump_envvars(request_rec *r) {
    r->content_type = "text/plain";
    //apr_send_http_header(r);
    //if (r->header_only)
    //    return OK;

    apr_table_do(iterate_func, r, r->subprocess_env, NULL);

    return OK;
}

And I call them:

    printf("In ap_headers_insert_output_filter\n");
    printf("In ap_headers_insert_output_filter: REQUEST_URI=[%s]\n", header_request_env_var(r, "REQUEST_URI") );
    printf("In ap_headers_insert_output_filter: About to call dump_request...");
    dump_request(r);
    printf("In ap_headers_insert_output_filter: Returned from calling dump_request...\n");
    printf("In ap_headers_insert_output_filter: About to call dump_envvars...");
    dump_envvars(r);
    printf("In ap_headers_insert_output_filter: Returned from calling dump_envvars...\n");

from inside the ap_headers_insert_output_filter() function in mod_headers (again, just an experiment).

The dump_request() does seem to return a bunch of the request headers, including one that I set using RequestHeader directive, but the dump_envvars() returned only one envvar, UNIQUE_ID.

Is that to be expected?  Is there somewhere else in the mod_headers.c code that I could put these dump_envvars() calls that would show more envvars?

Thanks,
Jim


---- ohaya@cox.net wrote: 
> Hi Sorin and Ben,
> 
> I found a list of variables somewhere, and just (probably unluckily) picked REMOTE_URI, just to see if retrieving any variable would work (an experiment).  Is there a list of environment variables that WOULD return something other than null for that call?
> 
> Thanks,
> Jim
> 
> 
> ---- Ben Noordhuis <in...@bnoordhuis.nl> wrote: 
> > On Mon, Jun 18, 2012 at 8:53 AM,  <oh...@cox.net> wrote:
> > > I added a call to header_request_env_var(r, "REMOTE_URI"), just to see what it got (running Apache in single-process mode):
> > >
> > > printf("REMOTE_URI=[%s]\n", header_request_env_var(r, "REMOTE_URI") );
> > >
> > > Then I pointed a browser to http://<myhost>/test, where /test was a <Location> with a RequestHeader (to trigger mod_headers) but I got:
> > >
> > > REMOTE_URI=[(null)]
> > >
> > > Shouldn't that be showing:
> > >
> > > REMOTE_URI=[/test]
> > >
> > > ??
> > 
> > Did you mean REMOTE_USER or REQUEST_URI? I don't think there's such a
> > thing as REMOTE_URI.
> 

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by oh...@cox.net.
Hi Sorin and Ben,

I found a list of variables somewhere, and just (probably unluckily) picked REMOTE_URI, just to see if retrieving any variable would work (an experiment).  Is there a list of environment variables that WOULD return something other than null for that call?

Thanks,
Jim


---- Ben Noordhuis <in...@bnoordhuis.nl> wrote: 
> On Mon, Jun 18, 2012 at 8:53 AM,  <oh...@cox.net> wrote:
> > I added a call to header_request_env_var(r, "REMOTE_URI"), just to see what it got (running Apache in single-process mode):
> >
> > printf("REMOTE_URI=[%s]\n", header_request_env_var(r, "REMOTE_URI") );
> >
> > Then I pointed a browser to http://<myhost>/test, where /test was a <Location> with a RequestHeader (to trigger mod_headers) but I got:
> >
> > REMOTE_URI=[(null)]
> >
> > Shouldn't that be showing:
> >
> > REMOTE_URI=[/test]
> >
> > ??
> 
> Did you mean REMOTE_USER or REQUEST_URI? I don't think there's such a
> thing as REMOTE_URI.


Re: How to access client certificate PEM and incoming request headers in a module?

Posted by Ben Noordhuis <in...@bnoordhuis.nl>.
On Mon, Jun 18, 2012 at 8:53 AM,  <oh...@cox.net> wrote:
> I added a call to header_request_env_var(r, "REMOTE_URI"), just to see what it got (running Apache in single-process mode):
>
> printf("REMOTE_URI=[%s]\n", header_request_env_var(r, "REMOTE_URI") );
>
> Then I pointed a browser to http://<myhost>/test, where /test was a <Location> with a RequestHeader (to trigger mod_headers) but I got:
>
> REMOTE_URI=[(null)]
>
> Shouldn't that be showing:
>
> REMOTE_URI=[/test]
>
> ??

Did you mean REMOTE_USER or REQUEST_URI? I don't think there's such a
thing as REMOTE_URI.

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by Sorin Manolache <so...@gmail.com>.
On 2012-06-18 08:53, ohaya@cox.net wrote:
> Hi,
>
> I'll look at ssl_var_lookup a little later, but I'm still messing around with mod_headers.c, tweaking it to understand how THAT is working :)...
>
> I added a call to header_request_env_var(r, "REMOTE_URI"), just to see what it got (running Apache in single-process mode):
>
> printf("REMOTE_URI=[%s]\n", header_request_env_var(r, "REMOTE_URI") );
>
> Then I pointed a browser to http://<myhost>/test, where /test was a <Location> with a RequestHeader (to trigger mod_headers) but I got:
>
> REMOTE_URI=[(null)]
>
> Shouldn't that be showing:
>
> REMOTE_URI=[/test]
>

How did you set the REMOTE_URI environment variable? I've grepped the 
apache sources and there's no occurrence of REMOTE_URI, so I assume that 
apache does not set it as part of its request processing.

S

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by oh...@cox.net.
---- Ben Noordhuis <in...@bnoordhuis.nl> wrote: 
> On Mon, Jun 18, 2012 at 5:45 AM,  <oh...@cox.net> wrote:
> > I haven't actually tried your suggestion yet, but, re. the SSL variables, I was looking at mod_headers.c, and in there, there are two separate functions:
> >
> > static const char *header_request_env_var(request_rec *r, char *a)
> > {
> >    const char *s = apr_table_get(r->subprocess_env,a);
> >
> >    if (s)
> >        return unwrap_header(r->pool, s);
> >    else
> >        return "(null)";
> > }
> >
> > static const char *header_request_ssl_var(request_rec *r, char *name)
> > {
> >    if (header_ssl_lookup) {
> >        const char *val = header_ssl_lookup(r->pool, r->server,
> >                                            r->connection, r, name);
> >        if (val && val[0])
> >            return unwrap_header(r->pool, val);
> >        else
> >            return "(null)";
> >    }
> >    else {
> >        return "(null)";
> >    }
> > }
> >
> > So, it seems like the method to get the SSL variables is different than the other environment variables?
> >
> > Or, does setting SSLOptions the way that you suggested cause the SSL variable so also exist in apr_table_get(r->subprocess_env, xxxx)?
> 
> Oh, I forgot about that. It's the ssl_var_lookup optional function,
> that might even work without having to tweak SSLOptions.


Hi,

I'll look at ssl_var_lookup a little later, but I'm still messing around with mod_headers.c, tweaking it to understand how THAT is working :)...

I added a call to header_request_env_var(r, "REMOTE_URI"), just to see what it got (running Apache in single-process mode):

printf("REMOTE_URI=[%s]\n", header_request_env_var(r, "REMOTE_URI") );

Then I pointed a browser to http://<myhost>/test, where /test was a <Location> with a RequestHeader (to trigger mod_headers) but I got:

REMOTE_URI=[(null)]

Shouldn't that be showing:

REMOTE_URI=[/test]

??

Thanks again,
Jim


Re: How to access client certificate PEM and incoming request headers in a module?

Posted by Ben Noordhuis <in...@bnoordhuis.nl>.
On Mon, Jun 18, 2012 at 5:45 AM,  <oh...@cox.net> wrote:
> I haven't actually tried your suggestion yet, but, re. the SSL variables, I was looking at mod_headers.c, and in there, there are two separate functions:
>
> static const char *header_request_env_var(request_rec *r, char *a)
> {
>    const char *s = apr_table_get(r->subprocess_env,a);
>
>    if (s)
>        return unwrap_header(r->pool, s);
>    else
>        return "(null)";
> }
>
> static const char *header_request_ssl_var(request_rec *r, char *name)
> {
>    if (header_ssl_lookup) {
>        const char *val = header_ssl_lookup(r->pool, r->server,
>                                            r->connection, r, name);
>        if (val && val[0])
>            return unwrap_header(r->pool, val);
>        else
>            return "(null)";
>    }
>    else {
>        return "(null)";
>    }
> }
>
> So, it seems like the method to get the SSL variables is different than the other environment variables?
>
> Or, does setting SSLOptions the way that you suggested cause the SSL variable so also exist in apr_table_get(r->subprocess_env, xxxx)?

Oh, I forgot about that. It's the ssl_var_lookup optional function,
that might even work without having to tweak SSLOptions.

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by oh...@cox.net.
---- ohaya@cox.net wrote: 
> 
> ---- Ben Noordhuis <in...@bnoordhuis.nl> wrote: 
> > On Sun, Jun 17, 2012 at 9:46 PM,  <oh...@cox.net> wrote:
> > > Hi,
> > >
> > > I am starting to look into implementing an Apache module that can use information from an incoming request, including several headers and the subject string from a client certificate to do authentication.
> > >
> > > I've been looking at the source for mod_auth_certificate, from https://modules.apache.org/, as a starting point.
> > >
> > > However, it looks like the way that mod_auth_certificate works is that it requires that there's an SSLUserName directive to put the client certificate DN into the Apache REMOTE_USER attribute, whereas I need the entire PEM for the client cert to do authentication that I'm trying to do.
> > >
> > > So I was wondering if it's possible for a module to access the SSL_CLIENT_S_DN and SSL_CLIENT_CERT environment variables, and if so, how?
> > 
> > They should be set in r->subprocess_env provided `SSLOptions
> > +StdEnvVars +ExportCertData` is set in the server or per-directory
> > config.
> > 
> > > Also, as mentioned my module would need to access several HTTP headers that are in the incoming requests.  How can it do that?
> > 
> > Look them up with `apr_table_get(r->headers_in, "X-Header-Name")`.
> 
> 
> Ben,
> 
> Thanks.  I'll give those a try.  We already the SSLOptions set as you mentioned, so assuming that I can figure out the coding (it's been a long time since I've done C/C++), that should work :)...
> 
> Jim


Hi,

I haven't actually tried your suggestion yet, but, re. the SSL variables, I was looking at mod_headers.c, and in there, there are two separate functions:

static const char *header_request_env_var(request_rec *r, char *a)
{
    const char *s = apr_table_get(r->subprocess_env,a);

    if (s)
        return unwrap_header(r->pool, s);
    else
        return "(null)";
}

static const char *header_request_ssl_var(request_rec *r, char *name)
{
    if (header_ssl_lookup) {
        const char *val = header_ssl_lookup(r->pool, r->server,
                                            r->connection, r, name);
        if (val && val[0])
            return unwrap_header(r->pool, val);
        else
            return "(null)";
    }
    else {
        return "(null)";
    }
}

So, it seems like the method to get the SSL variables is different than the other environment variables?

Or, does setting SSLOptions the way that you suggested cause the SSL variable so also exist in apr_table_get(r->subprocess_env, xxxx)?

Jim

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by oh...@cox.net.
---- Ben Noordhuis <in...@bnoordhuis.nl> wrote: 
> On Sun, Jun 17, 2012 at 9:46 PM,  <oh...@cox.net> wrote:
> > Hi,
> >
> > I am starting to look into implementing an Apache module that can use information from an incoming request, including several headers and the subject string from a client certificate to do authentication.
> >
> > I've been looking at the source for mod_auth_certificate, from https://modules.apache.org/, as a starting point.
> >
> > However, it looks like the way that mod_auth_certificate works is that it requires that there's an SSLUserName directive to put the client certificate DN into the Apache REMOTE_USER attribute, whereas I need the entire PEM for the client cert to do authentication that I'm trying to do.
> >
> > So I was wondering if it's possible for a module to access the SSL_CLIENT_S_DN and SSL_CLIENT_CERT environment variables, and if so, how?
> 
> They should be set in r->subprocess_env provided `SSLOptions
> +StdEnvVars +ExportCertData` is set in the server or per-directory
> config.
> 
> > Also, as mentioned my module would need to access several HTTP headers that are in the incoming requests.  How can it do that?
> 
> Look them up with `apr_table_get(r->headers_in, "X-Header-Name")`.


Ben,

Thanks.  I'll give those a try.  We already the SSLOptions set as you mentioned, so assuming that I can figure out the coding (it's been a long time since I've done C/C++), that should work :)...

Jim

Re: How to access client certificate PEM and incoming request headers in a module?

Posted by Ben Noordhuis <in...@bnoordhuis.nl>.
On Sun, Jun 17, 2012 at 9:46 PM,  <oh...@cox.net> wrote:
> Hi,
>
> I am starting to look into implementing an Apache module that can use information from an incoming request, including several headers and the subject string from a client certificate to do authentication.
>
> I've been looking at the source for mod_auth_certificate, from https://modules.apache.org/, as a starting point.
>
> However, it looks like the way that mod_auth_certificate works is that it requires that there's an SSLUserName directive to put the client certificate DN into the Apache REMOTE_USER attribute, whereas I need the entire PEM for the client cert to do authentication that I'm trying to do.
>
> So I was wondering if it's possible for a module to access the SSL_CLIENT_S_DN and SSL_CLIENT_CERT environment variables, and if so, how?

They should be set in r->subprocess_env provided `SSLOptions
+StdEnvVars +ExportCertData` is set in the server or per-directory
config.

> Also, as mentioned my module would need to access several HTTP headers that are in the incoming requests.  How can it do that?

Look them up with `apr_table_get(r->headers_in, "X-Header-Name")`.