X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2FPVE%2FCertificate.pm;h=c65fd315eabed9b9dcfbd9281a8141f3d1a5657f;hb=45a75161032914db05fc8896be25cda1eca245c3;hp=31a77223f83c556e393be3a3165ea168eda5ae1d;hpb=eb6262a6b746141bc67a6a8a90bfc728065db385;p=pve-common.git diff --git a/src/PVE/Certificate.pm b/src/PVE/Certificate.pm index 31a7722..c65fd31 100644 --- a/src/PVE/Certificate.pm +++ b/src/PVE/Certificate.pm @@ -179,15 +179,9 @@ sub der_to_pem { return "-----BEGIN $label-----\n$b64\n-----END $label-----\n"; } -my $ssl_die = sub { +my sub ssl_die { my ($msg) = @_; - Net::SSLeay::die_now($msg); -}; - -my $ssl_warn = sub { - my ($msg) = @_; - Net::SSLeay::print_errs(); - warn $msg if $msg; + Net::SSLeay::die_now("$msg\n"); }; my $read_certificate = sub { @@ -196,7 +190,7 @@ my $read_certificate = sub { die "'$cert_path' does not exist!\n" if ! -e $cert_path; my $bio = Net::SSLeay::BIO_new_file($cert_path, 'r') - or $ssl_die->("unable to read '$cert_path' - $!\n"); + or ssl_die("unable to read '$cert_path' - $!"); my $cert = Net::SSLeay::PEM_read_bio_X509($bio); Net::SSLeay::BIO_free($bio); @@ -208,9 +202,9 @@ my $read_certificate = sub { sub convert_asn1_to_epoch { my ($asn1_time) = @_; - $ssl_die->("invalid ASN1 time object\n") if !$asn1_time; + ssl_die("invalid ASN1 time object") if !$asn1_time; my $iso_time = Net::SSLeay::P_ASN1_TIME_get_isotime($asn1_time); - $ssl_die->("unable to parse ASN1 time\n") if $iso_time eq ''; + ssl_die("unable to parse ASN1 time") if $iso_time eq ''; return Date::Parse::str2time($iso_time); } @@ -228,6 +222,39 @@ sub get_certificate_fingerprint { return $fp; } +sub check_certificate_matches_key { + my ($cert_path, $key_path) = @_; + + die "No certificate path given!\n" if !$cert_path; + die "No certificate key path given!\n" if !$key_path; + + die "Certificate at '$cert_path' does not exist!\n" if ! -e $cert_path; + die "Certificate key '$key_path' does not exist!\n" if ! -e $key_path; + + my $ctx = Net::SSLeay::CTX_new() + or ssl_die("Failed to create SSL context in order to verify private key"); + + eval { + my $filetype = &Net::SSLeay::FILETYPE_PEM; + + Net::SSLeay::CTX_use_PrivateKey_file($ctx, $key_path, $filetype) + or ssl_die("Failed to load private key from '$key_path' into SSL context"); + + Net::SSLeay::CTX_use_certificate_file($ctx, $cert_path, $filetype) + or ssl_die("Failed to load certificate from '$cert_path' into SSL context"); + + Net::SSLeay::CTX_check_private_key($ctx) + or ssl_die("Failed to validate private key and certificate"); + }; + my $err = $@; + + Net::SSLeay::CTX_free($ctx); + + die $err if $err; + + return 1; +} + sub get_certificate_info { my ($cert_path) = @_; @@ -343,8 +370,8 @@ sub generate_csr { my ($bio, $pk, $req); my $cleanup = sub { - my ($warn, $die_msg) = @_; - $ssl_warn->() if $warn; + my ($die_msg, $no_warn) = @_; + Net::SSLeay::print_errs() if !$no_warn; Net::SSLeay::X509_REQ_free($req) if $req; Net::SSLeay::EVP_PKEY_free($pk) if $pk; @@ -356,75 +383,70 @@ sub generate_csr { # this unfortunately causes a small memory leak, since there is no # X509_NAME_free() (yet) my $name = Net::SSLeay::X509_NAME_new(); - $ssl_die->("Failed to allocate X509_NAME object\n") if !$name; + ssl_die("Failed to allocate X509_NAME object") if !$name; my $add_name_entry = sub { my ($k, $v) = @_; - if (!Net::SSLeay::X509_NAME_add_entry_by_txt($name, - $k, - &Net::SSLeay::MBSTRING_UTF8, - encode('utf-8', $v))) { - $cleanup->(1, "Failed to add '$k'='$v' to DN\n"); - } + + my $res = Net::SSLeay::X509_NAME_add_entry_by_txt( + $name, $k, &Net::SSLeay::MBSTRING_UTF8, encode('utf-8', $v)); + + $cleanup->("Failed to add '$k'='$v' to DN\n") if !$res; }; $add_name_entry->('CN', $common_name); for (qw(C ST L O OU)) { - if (defined(my $v = $attr{$_})) { + if (defined(my $v = $attr{$_})) { $add_name_entry->($_, $v); - } + } } if (defined($pem_key)) { my $bio_s_mem = Net::SSLeay::BIO_s_mem(); - $cleanup->(1, "Failed to allocate BIO_s_mem for private key\n") - if !$bio_s_mem; + $cleanup->("Failed to allocate BIO_s_mem for private key\n") if !$bio_s_mem; $bio = Net::SSLeay::BIO_new($bio_s_mem); - $cleanup->(1, "Failed to allocate BIO for private key\n") if !$bio; + $cleanup->("Failed to allocate BIO for private key\n") if !$bio; - $cleanup->(1, "Failed to write PEM-encoded key to BIO\n") + $cleanup->("Failed to write PEM-encoded key to BIO\n") if Net::SSLeay::BIO_write($bio, $pem_key) <= 0; $pk = Net::SSLeay::PEM_read_bio_PrivateKey($bio); - $cleanup->(1, "Failed to read private key into EVP_PKEY\n") if !$pk; + $cleanup->("Failed to read private key into EVP_PKEY\n") if !$pk; } else { $pk = Net::SSLeay::EVP_PKEY_new(); - $cleanup->(1, "Failed to allocate EVP_PKEY for private key\n") if !$pk; + $cleanup->("Failed to allocate EVP_PKEY for private key\n") if !$pk; my $rsa = Net::SSLeay::RSA_generate_key($bits, 65537); - $cleanup->(1, "Failed to generate RSA key pair\n") if !$rsa; + $cleanup->("Failed to generate RSA key pair\n") if !$rsa; - $cleanup->(1, "Failed to assign RSA key to EVP_PKEY\n") + $cleanup->("Failed to assign RSA key to EVP_PKEY\n") if !Net::SSLeay::EVP_PKEY_assign_RSA($pk, $rsa); } $req = Net::SSLeay::X509_REQ_new(); - $cleanup->(1, "Failed to allocate X509_REQ\n") if !$req; + $cleanup->("Failed to allocate X509_REQ\n") if !$req; - $cleanup->(1, "Failed to set subject name\n") + $cleanup->("Failed to set subject name\n") if (!Net::SSLeay::X509_REQ_set_subject_name($req, $name)); - $cleanup->(1, "Failed to add extensions to CSR\n") - if !Net::SSLeay::P_X509_REQ_add_extensions($req, - &Net::SSLeay::NID_key_usage => 'digitalSignature,keyEncipherment', - &Net::SSLeay::NID_basic_constraints => 'CA:FALSE', - &Net::SSLeay::NID_ext_key_usage => 'serverAuth,clientAuth', - &Net::SSLeay::NID_subject_alt_name => join(',', map { "DNS:$_" } @$san), - ); + Net::SSLeay::P_X509_REQ_add_extensions( + $req, + &Net::SSLeay::NID_key_usage => 'digitalSignature,keyEncipherment', + &Net::SSLeay::NID_basic_constraints => 'CA:FALSE', + &Net::SSLeay::NID_ext_key_usage => 'serverAuth,clientAuth', + &Net::SSLeay::NID_subject_alt_name => join(',', map { "DNS:$_" } @$san), + ) or $cleanup->("Failed to add extensions to CSR\n"); - $cleanup->(1, "Failed to set public key\n") - if !Net::SSLeay::X509_REQ_set_pubkey($req, $pk); + $cleanup->("Failed to set public key\n") if !Net::SSLeay::X509_REQ_set_pubkey($req, $pk); - $cleanup->(1, "Failed to set CSR version\n") - if !Net::SSLeay::X509_REQ_set_version($req, 2); + $cleanup->("Failed to set CSR version\n") if !Net::SSLeay::X509_REQ_set_version($req, 2); - $cleanup->(1, "Failed to sign CSR\n") - if !Net::SSLeay::X509_REQ_sign($req, $pk, $md); + $cleanup->("Failed to sign CSR\n") if !Net::SSLeay::X509_REQ_sign($req, $pk, $md); my $pk_pem = Net::SSLeay::PEM_get_string_PrivateKey($pk); my $req_pem = Net::SSLeay::PEM_get_string_X509_REQ($req); - $cleanup->(); + $cleanup->(undef, 1); return wantarray ? ($req_pem, $pk_pem) : $req_pem; }