|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Plack::Middleware::ClientCert;  | 
| 
2
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
1369
 | 
 use strict;  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
    | 
| 
3
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
14
 | 
 use warnings;  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
70
 | 
    | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
 
 | 
1045
 | 
 use parent qw(Plack::Middleware);  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
705
 | 
    | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '0.100';  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub client_cert  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  {  | 
| 
11
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
0
  
 | 
5
 | 
   my ($env) = @_;  | 
| 
12
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   my %cert = ();  | 
| 
13
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   my $prefix = 'client_';  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
15
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   my $ssl_env = "SSL_CLIENT_S_DN";  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
17
 | 
3
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
14
 | 
   my $dn = $env->{ CERT_SUBJECT } || $env->{ $ssl_env } || '';  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # If headers are passed in by a proxy, they are prefixed by HTTP_  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
22
 | 
3
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
11
 | 
   if (!$dn && $env->{ "HTTP_$ssl_env" }) {  | 
| 
23
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $ssl_env = "HTTP_$ssl_env";  | 
| 
24
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $dn = $env->{ $ssl_env };  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    }  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Apache on Linux does the parsing for us.  The parts to the DN are  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # all in SSL_CLIENT_S_DN_xx  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
31
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   my @keys = grep s/^${ssl_env}_(.*)/$1/, (keys %{ $env });  | 
| 
 
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
    | 
| 
32
 | 
3
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   if (@keys) {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
33
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     for my $key (@keys) {  | 
| 
34
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
       $env->{ $prefix . lc( $key ) } = $env->{ "${ssl_env}_${key}" };  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      }  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    }  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # The DN can be delimited by commas or slashes (/).  Assume commas unless  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # the very first character is a slash.  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   #  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   elsif ($dn =~ /^\//) {  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Iterate through the DN while there are still 'field=value' pairs  | 
| 
43
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     while ($dn =~ /=/) {  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       #  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Match the leading slash, then the field name, equals sign,  | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # and value.  Finally, match the next slash seperator or the  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # end of the line.  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       #  | 
| 
49
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
       $dn =~ s/^\/(.*?)=(.*?)(\/|$)/$3/;  | 
| 
50
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
       $env->{ $prefix . lc( $1 ) } = $2;  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      }  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    }  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   else {  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Iterate through the DN while there are still 'field=value' pairs  | 
| 
55
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     while ($dn =~ /=/) {  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       #  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # The first match is the field.   Then match 0 or 1 quotation mark(s).  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # The third match is the value.  Match the closed quote (or nothing).  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Finally, match the comma seperator and blank space, or the end  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       #  | 
| 
61
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
       $dn =~ s/^(.*?)=(\"*)(.*?)\2(,\s*|$)//;  | 
| 
62
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
       $env->{ $prefix . lc( $1 ) } = $3;  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      }  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    }  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Add serial number if appropriate  | 
| 
67
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $serial_key = $ssl_env;  | 
| 
68
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
   $serial_key =~ s/S_DN/M_SERIAL/;  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
3
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
19
 | 
   $env->{ "${prefix}serial" } = $env->{ $serial_key } || '';  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
72
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   return;  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  } # End of client_cert()  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub call {  | 
| 
77
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
1988
 | 
     my($self, $env) = @_;  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
79
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     client_cert( $env );  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
81
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     return $self->app->($env);  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |