Skip to content

Commit

Permalink
[backend] move X509 stuff from BSASN1.pm to BSX509.pm
Browse files Browse the repository at this point in the history
  • Loading branch information
mlschroe authored and coolo committed Nov 14, 2018
1 parent 902d7c5 commit 42b8c0c
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 31 deletions.
49 changes: 25 additions & 24 deletions src/backend/BSASN1.pm
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ use MIME::Base64 ();

use strict;


# x509 constants
our $UNIV = 0x00;
our $APPL = 0x40;
our $CONT = 0x80;
Expand All @@ -41,31 +39,15 @@ our $BIT_STRING = 0x03;
our $OCTET_STRING = 0x04;
our $NULL = 0x05;
our $OBJ_ID = 0x06;
our $REAL = 0x09;
our $ENUMERATED = 0x0a;
our $UTF8STRING = 0x0c;
our $SEQUENCE = 0x10;
our $SET = 0x11;
our $PRINTABLESTRING = 0x13;
our $UTCTIME = 0x17;
our $GENTIME = 0x18;

our $oid_common_name = asn1_obj_id(2, 5, 4, 3);
our $oid_country_name = asn1_obj_id(2, 5, 4, 6);
our $oid_org_name = asn1_obj_id(2, 5, 4, 10);
our $oid_org_unit_name = asn1_obj_id(2, 5, 4, 11);
our $oid_email_address = asn1_obj_id(1, 2, 840, 113549, 1, 9, 1);
our $oid_sha1 = asn1_obj_id(1, 3, 14, 3, 2, 26);
our $oid_sha256 = asn1_obj_id(2, 16, 840, 1, 101, 3, 4, 2, 1);
our $oid_sha512 = asn1_obj_id(2, 16, 840, 1, 101, 3, 4, 2, 3);
our $oid_id_dsa = asn1_obj_id(1, 2, 840, 10040, 4, 1);
our $oid_id_ec_public_key = asn1_obj_id(1, 2, 840, 10045, 2, 1);
our $oid_prime256v1 = asn1_obj_id(1, 2, 840, 10045, 3, 1, 7);
our $oid_rsaencryption = asn1_obj_id(1, 2, 840, 113549, 1, 1, 1);
our $oid_sha1withrsaencryption = asn1_obj_id(1, 2, 840, 113549, 1, 1, 5);
our $oid_sha256withrsaencryption = asn1_obj_id(1, 2, 840, 113549, 1, 1, 11);
our $oid_key_usage = asn1_obj_id(2, 5, 29, 15);
our $oid_basic_constraints = asn1_obj_id(2, 5, 29, 19);
our $oid_ext_key_usage = asn1_obj_id(2, 5, 29, 37);
our $oid_code_signing = asn1_obj_id(1, 3, 6, 1, 5, 5, 7, 3, 3);

sub utctime {
my ($t) = @_;
my @gt = gmtime($t || time());
Expand Down Expand Up @@ -175,10 +157,20 @@ sub asn1_octet_string {
}

sub asn1_tagged {
return asn1_pack($CONT | $CONS | $_[0], $_[1]);
return asn1_pack(($_[0] < 0x40 ? $CONT : 0) | $CONS | $_[0], $_[1]);
}

sub asn1_tagged_implicit {
my ($rest, $tag, $body) = asn1_unpack($_[1]);
return asn1_pack(($_[0] < 0x40 ? $CONT : 0) | ($tag & $CONS) | $_[0], $body).$rest;
}

# little unpack helpers (intag = 0 : any tag allowed)

sub asn1_gettag {
return (asn1_unpack(@_))[1];
}

# little unpack helpers
sub asn1_unpack_integer_mpi {
my ($in, $intag) = @_;
$intag = $INTEGER unless defined $intag;
Expand All @@ -188,11 +180,20 @@ sub asn1_unpack_integer_mpi {
}

sub asn1_unpack_sequence {
my ($in, $intag) = @_;
my ($in, $intag, $allowed) = @_;
$intag = $CONS | $SEQUENCE unless defined $intag;
(undef, undef, $in) = asn1_unpack($in, $intag ? $intag : undef, undef, 1);
my @ret;
my $tagbody;
if ($allowed) {
for my $all (@$allowed) {
return @ret, $in if $all && !ref($all) && $all == -1;
($in, undef, undef, $tagbody) = asn1_unpack($in, $all ? $all : undef);
push @ret, $tagbody;
}
die("tailing data at end of asn1 sequence\n") if $in ne '';
return @ret;
}
while ($in ne '') {
($in, undef, undef, $tagbody) = asn1_unpack($in);
push @ret, $tagbody;
Expand Down
15 changes: 8 additions & 7 deletions src/backend/BSTUF.pm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use Digest::SHA;
use BSConfiguration;
use BSUtil;
use BSASN1;
use BSX509;

use strict;

Expand All @@ -37,7 +38,7 @@ sub keydata2asn1 {
die("need an rsa pubkey\n") unless ($keydata->{'algo'} || '') eq 'rsa';
my $pubkey = BSASN1::asn1_sequence(BSASN1::asn1_integer_mpi($keydata->{'mpis'}->[0]->{'data'}), BSASN1::asn1_integer_mpi($keydata->{'mpis'}->[1]->{'data'}));
$pubkey = BSASN1::asn1_pack($BSASN1::BIT_STRING, pack('C', 0).$pubkey);
return BSASN1::asn1_sequence(BSASN1::asn1_sequence($BSASN1::oid_rsaencryption, BSASN1::asn1_null()), $pubkey);
return BSASN1::asn1_sequence(BSASN1::asn1_sequence($BSX509::oid_rsaencryption, BSASN1::asn1_null()), $pubkey);
}

sub rfc3339time {
Expand Down Expand Up @@ -66,22 +67,22 @@ sub mktbscert {
$serial .= pack("C", int(rand(256))) for (1, 2, 3, 4, 5, 6, 7);
my $certversion = BSASN1::asn1_tagged(0, BSASN1::asn1_integer(2));
my $certserial = BSASN1::asn1_integer_mpi($serial);
my $sigalgo = BSASN1::asn1_sequence($BSASN1::oid_sha256withrsaencryption, BSASN1::asn1_null());
my $cnattr = BSASN1::asn1_sequence($BSASN1::oid_common_name, BSASN1::asn1_pack($BSASN1::UTF8STRING, $cn));
my $sigalgo = BSASN1::asn1_sequence($BSX509::oid_sha256withrsaencryption, BSASN1::asn1_null());
my $cnattr = BSASN1::asn1_sequence($BSX509::oid_common_name, BSASN1::asn1_pack($BSASN1::UTF8STRING, $cn));
my $issuer = BSASN1::asn1_sequence(BSASN1::asn1_set($cnattr));
my $validity = BSASN1::asn1_sequence(BSASN1::asn1_utctime($not_before), BSASN1::asn1_utctime($not_after));
my $critical = BSASN1::asn1_boolean(1);
my $basic_constraints = BSASN1::asn1_sequence($BSASN1::oid_basic_constraints, $critical, BSASN1::asn1_octet_string(BSASN1::asn1_sequence()));
my $key_usage = BSASN1::asn1_sequence($BSASN1::oid_key_usage, $critical, BSASN1::asn1_octet_string(BSASN1::asn1_pack($BSASN1::BIT_STRING, pack("CC", 5, 160))));
my $ext_key_usage = BSASN1::asn1_sequence($BSASN1::oid_ext_key_usage, BSASN1::asn1_octet_string(BSASN1::asn1_sequence($BSASN1::oid_code_signing)));
my $basic_constraints = BSASN1::asn1_sequence($BSX509::oid_basic_constraints, $critical, BSASN1::asn1_octet_string(BSASN1::asn1_sequence()));
my $key_usage = BSASN1::asn1_sequence($BSX509::oid_key_usage, $critical, BSASN1::asn1_octet_string(BSASN1::asn1_pack($BSASN1::BIT_STRING, pack("CC", 5, 160))));
my $ext_key_usage = BSASN1::asn1_sequence($BSX509::oid_ext_key_usage, BSASN1::asn1_octet_string(BSASN1::asn1_sequence($BSX509::oid_code_signing)));
my $extensions = BSASN1::asn1_tagged(3, BSASN1::asn1_sequence($basic_constraints, $key_usage, $ext_key_usage));
my $tbscert = BSASN1::asn1_sequence($certversion, $certserial, $sigalgo, $issuer, $validity, $issuer, $subjectkeyinfo, $extensions);
return $tbscert;
}

sub mkcert {
my ($tbscert, $signargs) = @_;
my $sigalgo = BSASN1::asn1_sequence($BSASN1::oid_sha256withrsaencryption, BSASN1::asn1_null());
my $sigalgo = BSASN1::asn1_sequence($BSX509::oid_sha256withrsaencryption, BSASN1::asn1_null());
my $signature = sign($tbscert, $signargs);
my $cert = BSASN1::asn1_sequence($tbscert, $sigalgo, BSASN1::asn1_pack($BSASN1::BIT_STRING, pack("C", 0), $signature));
return BSASN1::der2pem($cert, 'CERTIFICATE');
Expand Down
107 changes: 107 additions & 0 deletions src/backend/BSX509.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#
# Copyright (c) 2017 SUSE Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (see the file COPYING); if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#
################################################################
#
# certificate/pubkey definitions and helper functions
#

package BSX509;

use BSASN1;

use strict;

our $oid_common_name = BSASN1::asn1_obj_id(2, 5, 4, 3);
our $oid_country_name = BSASN1::asn1_obj_id(2, 5, 4, 6);
our $oid_org_name = BSASN1::asn1_obj_id(2, 5, 4, 10);
our $oid_org_unit_name = BSASN1::asn1_obj_id(2, 5, 4, 11);
our $oid_email_address = BSASN1::asn1_obj_id(1, 2, 840, 113549, 1, 9, 1);
our $oid_sha1 = BSASN1::asn1_obj_id(1, 3, 14, 3, 2, 26);
our $oid_sha256 = BSASN1::asn1_obj_id(2, 16, 840, 1, 101, 3, 4, 2, 1);
our $oid_sha512 = BSASN1::asn1_obj_id(2, 16, 840, 1, 101, 3, 4, 2, 3);
our $oid_id_dsa = BSASN1::asn1_obj_id(1, 2, 840, 10040, 4, 1);
our $oid_id_ec_public_key = BSASN1::asn1_obj_id(1, 2, 840, 10045, 2, 1);
our $oid_prime256v1 = BSASN1::asn1_obj_id(1, 2, 840, 10045, 3, 1, 7);
our $oid_rsaencryption = BSASN1::asn1_obj_id(1, 2, 840, 113549, 1, 1, 1);
our $oid_sha1withrsaencryption = BSASN1::asn1_obj_id(1, 2, 840, 113549, 1, 1, 5);
our $oid_sha256withrsaencryption = BSASN1::asn1_obj_id(1, 2, 840, 113549, 1, 1, 11);
our $oid_key_usage = BSASN1::asn1_obj_id(2, 5, 29, 15);
our $oid_basic_constraints = BSASN1::asn1_obj_id(2, 5, 29, 19);
our $oid_ext_key_usage = BSASN1::asn1_obj_id(2, 5, 29, 37);
our $oid_code_signing = BSASN1::asn1_obj_id(1, 3, 6, 1, 5, 5, 7, 3, 3);

sub keydata_getmpi {
my ($bits) = @_;
my $p = BSASN1::asn1_unpack_integer_mpi($bits);
my $nb = length($p) * 8;
if ($nb) {
my $first = unpack('C', $p);
$first < $_ && $nb-- for (128, 64, 32, 16, 8, 4, 2);
}
return { 'bits' => $nb, 'data' => $p };
}

sub pubkey2keydata {
my ($pkder) = @_;
my ($algoident, $bits) = BSASN1::asn1_unpack_sequence($pkder);
my ($algooid, $algoparams) = BSASN1::asn1_unpack_sequence($algoident);
my $algo;
if ($algooid eq $BSASN1::oid_rsaencryption) {
$algo = 'rsa';
} elsif ($algooid eq $BSASN1::oid_id_dsa) {
$algo = 'dsa';
} elsif ($algooid eq $BSASN1::oid_id_ec_public_key) {
$algo = 'ecdsa';
} else {
die("unknown pubkey algorithm\n");
}
(undef, undef, $bits) = BSASN1::asn1_unpack($bits, $BSASN1::BIT_STRING);
die("bits does not start with 0\n") unless unpack('C', $bits) == 0;
$bits = substr($bits, 1);
my @mpis;
my $res = { 'algo' => $algo };
my $nbits;
if ($algo eq 'dsa') {
push @mpis, keydata_getmpi($_) for BSASN1::asn1_unpack_sequence($algoparams);
push @mpis, keydata_getmpi($bits);
$nbits = $mpis[-1]->{'bits'};
} elsif ($algo eq 'rsa') {
push @mpis, keydata_getmpi($_) for BSASN1::asn1_unpack_sequence($bits);
$nbits = $mpis[0]->{'bits'};
} elsif ($algo eq 'ecdsa') {
my $curve;
(undef, undef, undef, $curve) = BSASN1::asn1_unpack($algoparams, $BSASN1::OBJ_ID, 1);
if ($curve && $curve eq $BSASN1::oid_prime256v1) {
$res->{'curve'} = 'prime256v1';
$nbits = 256;
} elsif (length($bits) > 1) {
my $f = unpack('C', $bits);
if ($f == 2 || $f == 3) {
$nbits = (length($bits) - 1) * 8;
} elsif ($f == 4) {
$nbits = (length($bits) - 1) / 2 * 8;
}
}
$res->{'point'} = $bits;
}
$res->{'mpis'} = \@mpis if @mpis;
$res->{'keysize'} = ($nbits + 31) & ~31 if $nbits;
return $res;
}

1;

0 comments on commit 42b8c0c

Please sign in to comment.