1package Crypt::Perl::PK;
2
3use strict;
4use warnings;
5
6=encoding utf-8
7
8=head1 NAME
9
10Crypt::Perl::PK - Public-key cryptography logic
11
12=head1 SYNOPSIS
13
14    #Will be an instance of the appropriate Crypt::Perl key class,
15    #i.e., one of:
16    #
17    #   Crypt::Perl::RSA::PrivateKey
18    #   Crypt::Perl::RSA::PublicKey
19    #   Crypt::Perl::ECDSA::PrivateKey
20    #   Crypt::Perl::ECDSA::PublicKey
21    #   Crypt::Perl::Ed25519::PrivateKey
22    #   Crypt::Perl::Ed25519::PublicKey
23    #
24    my $key_obj = Crypt::Perl::PK::parse_jwk( { .. } );
25
26    #Likewise. Feed it public or private, DER or PEM format,
27    #RSA or ECDSA.
28    my $key_obj = Crypt::Perl::PK::parse_key( $octet_string );
29
30=head1 DISCUSSION
31
32As of now there’s not much of interest to find here except
33parsing of L<JWK|https://tools.ietf.org/html/rfc7517>s.
34
35=cut
36
37use Try::Tiny;
38
39use Module::Load ();
40
41use Crypt::Perl::X ();
42
43sub parse_key {
44    my ($der_or_pem) = @_;
45
46    if (ref $der_or_pem) {
47        die Crypt::Perl::X::create('Generic', "Need unblessed octet string, not “$der_or_pem”!");
48    }
49
50    my $obj;
51
52    for my $alg ( qw( RSA Ed25519 ECDSA ) ) {
53        my $module = "Crypt::Perl::$alg\::Parse";
54        Module::Load::load($module);
55
56        try {
57            $obj = $module->can('private')->($der_or_pem);
58        }
59        catch {
60            try {
61                $obj = $module->can('public')->($der_or_pem);
62            }
63        };
64
65        return $obj if $obj;
66    }
67
68    die Crypt::Perl::X::create('Generic', "Unrecognized key: “$der_or_pem”");
69}
70
71sub parse_jwk {
72    my ($hr) = @_;
73
74    if ('HASH' ne ref $hr) {
75        die Crypt::Perl::X::create('InvalidJWK', $hr);
76    }
77
78    my $kty = $hr->{'kty'};
79
80    if ($kty) {
81        my $module;
82
83        if ($kty eq 'RSA') {
84            $module = 'Crypt::Perl::RSA::Parse';
85
86        }
87        elsif ($kty eq 'OKP') {
88            if ($hr->{'crv'} ne 'Ed25519') {
89                die Crypt::Perl::X::create('Generic', "Unrecognized “crv” ($hr->{'crv'}) for key type “$kty”!");
90            }
91
92            $module = 'Crypt::Perl::Ed25519::Parse';
93        }
94        elsif ($kty eq 'EC') {
95            $module = 'Crypt::Perl::ECDSA::Parse';
96        }
97        else {
98            die Crypt::Perl::X::create('UnknownJTKkty', $kty);
99        }
100
101        Module::Load::load($module);
102
103        return $module->can('jwk')->($hr);
104    }
105
106    die Crypt::Perl::X::create('InvalidJWK', %$hr);
107}
108
1091;
110