Factor out userid validation from MSVA.pm into Crypto::Monkeysphere::Validator.
[monkeysphere-validation-agent.git] / Crypt / Monkeysphere / Validator.pm
1 package Crypt::Monkeysphere::Validator;
2 use Carp;
3 use strict;
4 use warnings;
5
6 use parent 'Crypt::Monkeysphere::Keyserver';
7
8 sub new {
9   my $class=shift;
10   my %opts=@_;
11
12   my $self=$class->SUPER::new(%opts);
13
14   $self->{findall} = $opts{findall} || 0;
15   $self->{context}=$opts{context} || 'ssh';
16
17   return $self;
18 }
19
20 sub test_capable {
21   my $self=shift;
22   my $subkey=shift;
23
24   if ($self->{context} eq 'e-mail') {
25     if ($subkey->usage_flags =~ /s/) {
26       $self->log('verbose', "...and is signing-capable...\n");
27       return 1;
28     } else {
29       $self->log('verbose', "...but is not signing-capable (%s).\n",$subkey->usage_flags);
30     }
31   } else {
32     if ($subkey->usage_flags =~ /a/) {
33       $self->log('verbose', "...and is authentication-capable...\n");
34       return 1;
35     } else {
36       $self->log('verbose', "...but is not authentication-capable (%s).\n",$subkey->usage_flags);
37     }
38   }
39   return 0;
40 }
41
42 sub query{
43   my $self=shift;
44   my %opts=@_;
45
46   my $uid=$opts{uid} || croak "uid argument is mandatory";
47   my $fpr=$opts{fpr};
48   my $key=$opts{key};
49
50   my $gpgquery = defined($fpr) ?  '0x'.$fpr : '='.$uid;
51
52   my $ret= { valid_keys => [],
53              subvalid_keys => [] };
54
55   # setup variables
56   my $lastloop = 0;
57   my $foundvalid = 0;
58
59   if ($self->{kspolicy} eq 'always') {
60     if (defined $fpr) {
61       $self->fetch_fpr($fpr);
62     } else {
63       $self->fetch_uid($uid);
64     }
65     $lastloop = 1;
66   } elsif ($self->{kspolicy} eq 'never') {
67     $lastloop = 1;
68   }
69
70   while (1) {
71     foreach my $gpgkey ($self->{gnupg}->get_public_keys($gpgquery)) {
72       my $validity = '-';
73       foreach my $tryuid ($gpgkey->user_ids) {
74         if ($tryuid->as_string eq $uid) {
75           $validity = $tryuid->validity;
76         }
77       }
78       # treat primary keys just like subkeys:
79       foreach my $subkey ($gpgkey, @{$gpgkey->subkeys}) {
80           if ((!defined($key) && (!defined($fpr))) ||
81               (defined($key) && $self->keycomp($key, $subkey)) ||
82               (defined($fpr) && ($subkey->fingerprint->as_hex_string eq $fpr))) {
83             $self->log('verbose', "key 0x%s matches...\n",$subkey->hex_id);
84             if ($self->test_capable($subkey) ) {
85               if ($validity =~ /^[fu]$/) {
86                 $foundvalid = 1;
87                 $self->log('verbose', "...and is fully valid!\n");
88                 push(@{$ret->{valid_keys}},
89                      { fingerprint => $subkey->fingerprint, val => $validity });
90                 last unless($self->{findall});
91               } else {
92                 $self->log('verbose', "...but is not fully valid (%s).\n",$validity);
93                 push(@{$self->{subvalid_keys}},
94                      {fingerprint => $subkey->fingerprint, val => $validity }) if $lastloop;
95               }
96             }
97           }
98         }
99         last if ($foundvalid);
100       }
101       if ($lastloop || $foundvalid) {
102         last;
103       } else {
104         if (!$foundvalid) {
105           if (defined $fpr) {
106             $self->fetch_fpr($fpr);
107           } else {
108             $self->fetch_uid($uid);
109           }
110         }
111         $lastloop = 1;
112       }
113     }
114
115   return $ret;
116
117 }
118
119 sub keycomp {
120   my $self=shift;
121   my $rsakey = shift;
122   my $gpgkey = shift;
123
124   if ($gpgkey->algo_num != 1) {
125     my $self->log('verbose', "Monkeysphere only does RSA keys.  This key is algorithm #%d\n", $gpgkey->algo_num);
126     } else {
127       if ($rsakey->{exponent}->bcmp($gpgkey->pubkey_data->[1]) == 0 &&
128           $rsakey->{modulus}->bcmp($gpgkey->pubkey_data->[0]) == 0) {
129         return 1;
130       }
131     }
132     return 0;
133   }
134
135 1;