|
|
- Author: Daniel F. Dickinson <cshored@thecshore.com>
- Date: Sun Jan 27 01:04:25 2019 -0500
-
- gitolite: Eliminate the need for ssh-keygen dependency
-
- Previously gitolite used ssh-keygen to generate fingerprints
- from OpenSSH keys to ensure non-duplication of keys when
- processing them to create / manage user ssh access to the
- git repositories. This ends up depending on openssl,
- which is large and unnecessary when we are running on an
- embedded distro such as OpenWrt.
-
- Signed-off-by: Daniel F. Dickinson <cshored@thecshore.com>
- --- a/src/lib/Gitolite/Common.pm
- +++ b/src/lib/Gitolite/Common.pm
- @@ -26,6 +26,8 @@ package Gitolite::Common;
- use Exporter 'import';
- use File::Path qw(mkpath);
- use File::Temp qw(tempfile);
- +use MIME::Base64 qw(decode_base64);
- +use Digest::SHA qw(sha256_base64);
- use Carp qw(carp cluck croak confess);
-
- use strict;
- @@ -352,43 +354,82 @@ sub logger_plus_stderr {
- }
-
- # ----------------------------------------------------------------------
- +# Decode OpenSSH key
- +# If the key cannot be parsed it will be undef
- +# Returns (algorithm_name, algo_data1, algo_data2, ...)
- +sub ssh_decode_key($) {
- + my $key = shift;
- + my $keydata = decode_base64($key);
- + my @keyparts = ();
- + my $partlen;
- + my $algorithm;
- + my $data;
- + my $pos = 0;
- + $partlen = unpack('N', substr $keydata, $pos, 4) or return undef;
- + $algorithm = substr $keydata, $pos + 4, $partlen or return undef;
- + $pos = $pos + 4 + $partlen;
- + while ( $pos <= length($keydata) ) {
- + $partlen = unpack('N', substr $keydata, $pos, 4) or last;
- + $data = unpack('s>*', substr $keydata, $pos + 4, 4) or last;
- + $pos = $pos + 4 + $partlen;
- + push @keyparts, $data;
- + }
- + return ( $algorithm, @keyparts );
- +}
- +
- +# ----------------------------------------------------------------------
- +# Parse OpenSSH line
- +# If the file cannot be parsed it will be undef
- +# Returns (restrictions, algorithm, PEMkey, comment)
- +sub ssh_parse_line($) {
- + my $ssh_line = shift;
- + my @ssh_parts = split / /, $ssh_line, 5;
- + if (scalar @ssh_parts < 4) {
- + @ssh_parts = ('', @ssh_parts);
- + }
- + if (scalar @ssh_parts > 4) {
- + @ssh_parts = @ssh_parts[0,3]
- + }
- + if (scalar @ssh_parts < 4) {
- + @ssh_parts = undef;
- + }
- + return ( @ssh_parts );
- +}
- +
- +# ----------------------------------------------------------------------
- +# Get the SSH fingerprint of a line of text
- +# If the fingerprint cannot be parsed, it will be undef
- +# In a scalar context, returns the fingerprint
- +# In a list context, returns (fingerprint, output) where output
- +# is the parsed input line (less algorithm)
- +sub ssh_fingerprint_line($) {
- + my $ssh_line = shift;
- + my @parsed_line = ssh_parse_line($ssh_line) or return undef;
- + my @ssh_parts = ssh_decode_key($parsed_line[2]) or return undef;
- + ( $parsed_line[1] eq $ssh_parts[0] ) or die "algorithm mismatch: $parsed_line[1] vs. $ssh_parts[0]";
- + my $fp = sha256_base64(join(' ', @ssh_parts[1,-1]));
- + return wantarray ? ($fp, join(' ', @ssh_parts[1,-1])) : $fp;
- +}
- +
- +# ----------------------------------------------------------------------
- # Get the SSH fingerprint of a file
- # If the fingerprint cannot be parsed, it will be undef
- # In a scalar context, returns the fingerprint
- # In a list context, returns (fingerprint, output) where output
- -# is the raw output of the ssh-keygen command
- -sub ssh_fingerprint_file {
- +# is the raw input line
- +sub ssh_fingerprint_file($) {
- my $in = shift;
- -f $in or die "file not found: $in\n";
- my $fh;
- - open( $fh, "ssh-keygen -l -f $in |" ) or die "could not fork: $!\n";
- + open( $fh, $in ) or die "could not open $in: $!\n";
- my $output = <$fh>;
- chomp $output;
- - # dbg("fp = $fp");
- close $fh;
- # Return a valid fingerprint or undef
- - my $fp = undef;
- - if($output =~ /((?:MD5:)?(?:[0-9a-f]{2}:){15}[0-9a-f]{2})/i or
- - $output =~ m{((?:RIPEMD|SHA)\d+:[A-Za-z0-9+/=]+)}i) {
- - $fp = $1;
- - }
- + my $fp = ssh_fingerprint_line($output);
- return wantarray ? ($fp, $output) : $fp;
- }
-
- -# Get the SSH fingerprint of a line of text
- -# If the fingerprint cannot be parsed, it will be undef
- -# In a scalar context, returns the fingerprint
- -# In a list context, returns (fingerprint, output) where output
- -# is the raw output of the ssh-keygen command
- -sub ssh_fingerprint_line {
- - my ( $fh, $fn ) = tempfile();
- - print $fh shift() . "\n";
- - close $fh;
- - my ($fp,$output) = ssh_fingerprint_file($fn);
- - unlink $fn;
- - return wantarray ? ($fp,$output) : $fp;
- -}
- -
- # ----------------------------------------------------------------------
-
- # bare-minimum subset of 'Tsh' (see github.com/sitaramc/tsh)
|