1package OpenXPKI::Server::API2::Plugin::Crypto::generate_key;
2use OpenXPKI::Server::API2::EasyPlugin;
3
4=head1 NAME
5
6OpenXPKI::Server::API2::Plugin::Crypto::generate_key
7
8=cut
9
10# Project modules
11use OpenXPKI::Debug;
12use OpenXPKI::Server::Context qw( CTX );
13use OpenXPKI::Server::API2::Types;
14
15
16
17=head1 COMMANDS
18
19=head2 generate_key
20
21Creates a new cryptographic key and returns it encrypted representation in PEM
22format.
23
24B<Parameters>
25
26=over
27
28=item * C<password> I<Str> - passwort for key encryption. Required.
29
30=item * C<key_alg> I<Str> - key algorithm, e.g. "RSA", "DSA", "EC" etc. Default: "RSA"
31
32=item * C<enc_alg> I<Str> - encryption algorithm, e.g. "AES256" etc. Default:
33crypto backend's default
34
35=item * C<key_length> I<Int> - only RSA/DSA: key length. Default: 2048
36
37=item * C<curve> I<Str> - only EC: curve name. Required.
38
39=item * C<pkeyopt> I<HashRef>|I<ArrayRef> - more options to directly pass to OpenSSL.
40If specified, these option win over other parameters
41(e.g. C<options-E<gt>{rsa_keygen_bits}> wins over C<key_length>)
42For some combinations openssl needs a defined order of the option params,
43if this is required pass a list of hashes. Otherwise a hash with key/values
44will also do.
45
46=item * C<paramset> I<Str> - PEM encoded parameter set whose contents will be
47passed to C<openssl genpkey -paramfile ...>
48
49B<Changes compared to API v1:>
50
51The previous parameter C<PARAMS> was removed. The hash keys used in it are now
52"first class" parameters:
53
54    # old
55    PARAMS => {
56        PKEYOPT    => { ... },
57        KEY_LENGTH => $len,
58        ECPARAM    => $pem_ec_param,
59        DSAPARAM   => $pem_dsa_param,
60        CURVE_NAME => $curve,
61    }
62    # new
63    key_length  => $len,
64    pkeyopt     => { p1 => v1, p2 => v2 } or [{ p1 => v1 }, { p2 => v2 }],
65    paramset    => $pem_ec_param, # or $pem_dsa_param
66    curve       => $curve,
67
68The previously unused parameter C<ISSUER> was removed.
69
70=back
71
72=cut
73command "generate_key" => {
74    password    => { isa => 'Str', required => 1, },
75    key_alg     => { isa => 'Str', default => 'rsa' },
76    key_length  => { isa => 'Int', default => 2048 },
77    curve       => { isa => 'Str', },
78    enc_alg     => { isa => 'Str', },
79    pkeyopt     => { isa => 'HashRef|ArrayRef', },
80    paramset    => { isa => 'PEM', },
81} => sub {
82    my ($self, $params) = @_;
83    my $key_alg = lc($params->key_alg);
84    my $paramset = $params->paramset;
85
86    my $token = $self->api->get_default_token();
87
88    # prepare command definition
89    my $command = {
90         COMMAND => 'create_pkey',
91         KEY_ALG => $key_alg,
92         $params->has_enc_alg ? (ENC_ALG => $params->enc_alg) : (),
93         PASSWD  => $params->password,
94    };
95
96    # RSA
97    if ($key_alg eq "rsa") {
98        $command->{PKEYOPT} = [{ rsa_keygen_bits => $params->key_length }];
99    }
100    # EC
101    elsif ($key_alg eq "ec") {
102        # explicit parameter set is given
103        if ($paramset) {
104            $command->{PARAM} = $paramset;
105            delete $command->{KEY_ALG};
106        # curve name is given, also forces named_curve to be set
107        } elsif ($params->curve) {
108            $command->{PKEYOPT} = [{ ec_paramgen_curve => $params->curve }, { ec_param_enc => "named_curve" }];
109        } elsif (!$params->has_pkeyopt) {
110            OpenXPKI::Exception->throw(message => 'Either curve, paramset or pkeyopts must be given for EC');
111        }
112    }
113    # DSA
114    elsif ($key_alg eq "dsa") {
115        if (not $paramset) {
116            $paramset = $token->command({
117                COMMAND => 'create_params',
118                TYPE    => 'DSA',
119                PKEYOPT => [{ dsa_paramgen_bits => $params->key_length }]
120            })
121            or OpenXPKI::Exception->throw(message => 'Error generating DSA parameter set');
122        }
123        $command->{PARAM} = $paramset;
124        delete $command->{KEY_ALG};
125    }
126
127    # add additional options
128    if ($params->has_pkeyopt) {
129        my $opt = $params->pkeyopt;
130        if (ref $opt eq 'ARRAY') {
131            push @{$command->{PKEYOPT}}, @{$opt};
132        } elsif (ref $opt eq 'HASH') {
133            push @{$command->{PKEYOPT}}, $opt ;
134        } else {
135             OpenXPKI::Exception->throw(message => 'Unsupported format for pkeyopt');
136        }
137    }
138
139    CTX('log')->audit('key')->info("generating private key", { key_alg => $key_alg });
140
141    ##! 16: $command
142    return $token->command($command);
143};
144
145__PACKAGE__->meta->make_immutable;
146