[Pkg-privacy-commits] [Git][pkg-privacy-team/monkeysphere][dropping-keytrans] 4 commits: use bash variable substitution to avoid more perl
Daniel Kahn Gillmor
dkg at debian.org
Fri May 17 08:01:48 BST 2019
Daniel Kahn Gillmor pushed to branch dropping-keytrans at Privacy Maintainers / monkeysphere
Commits:
470abb02 by Daniel Kahn Gillmor at 2019-05-17T06:01:25Z
use bash variable substitution to avoid more perl
- - - - -
b670bc3a by Daniel Kahn Gillmor at 2019-05-17T06:59:21Z
avoid perl for base64-encoding
- - - - -
1d6dc18b by Daniel Kahn Gillmor at 2019-05-17T06:59:56Z
Drop checkperms perlscript for bash function
We implement checkperms using bash and POSIX-style find. This is the
last bit of perl dependency that remains.
- - - - -
27fa1b30 by Daniel Kahn Gillmor at 2019-05-17T07:00:29Z
drop keytrans (openpgp2{spki,pem,ssh}, pem2openpgp)
These conversion utilities only support RSA, and they're not widely
used outside the monkeysphere project.
As of now, the monkeysphere development branch doesn't even need them,
so we can drop them entirely.
- - - - -
13 changed files:
- Makefile
- README
- − man/man1/openpgp2ssh.1
- − man/man1/pem2openpgp.1
- man/man7/monkeysphere.7
- packaging/macports/Portfile
- src/monkeysphere-host
- − src/share/checkperms
- src/share/common
- − src/share/keytrans
- src/share/ma/setup
- tests/basic
- − tests/keytrans
Changes:
=====================================
Makefile
=====================================
@@ -73,12 +73,6 @@ install: all installman
install src/monkeysphere-authentication-keys-for-user $(DESTDIR)$(PREFIX)/share/monkeysphere
install -m 0644 src/share/common $(DESTDIR)$(PREFIX)/share/monkeysphere
install -m 0644 replaced/src/share/defaultenv $(DESTDIR)$(PREFIX)/share/monkeysphere
- install -m 0755 src/share/checkperms $(DESTDIR)$(PREFIX)/share/monkeysphere
- install -m 0755 src/share/keytrans $(DESTDIR)$(PREFIX)/share/monkeysphere
- ln -sf ../share/monkeysphere/keytrans $(DESTDIR)$(PREFIX)/bin/pem2openpgp
- ln -sf ../share/monkeysphere/keytrans $(DESTDIR)$(PREFIX)/bin/openpgp2ssh
- ln -sf ../share/monkeysphere/keytrans $(DESTDIR)$(PREFIX)/bin/openpgp2pem
- ln -sf ../share/monkeysphere/keytrans $(DESTDIR)$(PREFIX)/bin/openpgp2spki
install -m 0755 src/agent-transfer/agent-transfer $(DESTDIR)$(PREFIX)/bin
install -m 0744 replaced/src/transitions/* $(DESTDIR)$(PREFIX)/share/monkeysphere/transitions
install -m 0644 src/transitions/README.txt $(DESTDIR)$(PREFIX)/share/monkeysphere/transitions
@@ -97,15 +91,13 @@ installman: $(REPLACED_COMPRESSED_MANPAGES)
install replaced/man/man1/* $(DESTDIR)$(MANPREFIX)/man1
install replaced/man/man7/* $(DESTDIR)$(MANPREFIX)/man7
install replaced/man/man8/* $(DESTDIR)$(MANPREFIX)/man8
- ln -sf openpgp2ssh.1.gz $(DESTDIR)$(MANPREFIX)/man1/openpgp2pem.1.gz
- ln -sf openpgp2ssh.1.gz $(DESTDIR)$(MANPREFIX)/man1/openpgp2spki.1.gz
# this target depends on you having the monkeysphere-docs
# repo checked out as a peer of your monkeysphere repo.
releasenote:
../monkeysphere-docs/utils/build-releasenote
-test: test-keytrans test-basic test-ed25519
+test: test-basic test-ed25519
check: test
@@ -115,7 +107,4 @@ test-basic: src/agent-transfer/agent-transfer
test-ed25519: src/agent-transfer/agent-transfer
MONKEYSPHERE_TEST_NO_EXAMINE=true MONKEYSPHERE_TEST_USE_ED25519=true ./tests/basic
-test-keytrans: src/agent-transfer/agent-transfer
- MONKEYSPHERE_TEST_NO_EXAMINE=true ./tests/keytrans
-
.PHONY: all tarball debian-package freebsd-distinfo clean install installman releasenote test check
=====================================
README
=====================================
@@ -20,7 +20,9 @@ Dependencies
Monkeysphere depends on:
* GnuPG >= 2.1.17
+ * find (POSIX or GNU should both work)
* Perl
* lockfile-progs or procmail's lockfile
* Bash
* OpenSSH's ssh-keygen utility (>= 6.0)
+ * base64 (coreutils or fourmilab)
=====================================
man/man1/openpgp2ssh.1 deleted
=====================================
@@ -1,103 +0,0 @@
-.\" -*- nroff -*-
-.Dd $Mdocdate: January 18, 2013 $
-.Dt OPENPGP2SSH 1
-.Os
-.Sh NAME
-openpgp2ssh
-.Nd translate OpenPGP keys to SSH keys
-.Sh SYNOPSIS
-.Nm openpgp2ssh < mykey.gpg
-.Pp
-.Nm gpg \-\-export $KEYID | openpgp2ssh $KEYID
-.Pp
-.Nm gpg \-\-export $KEYID | openpgp2pem $KEYID
-.Pp
-.Nm gpg \-\-export $KEYID | openpgp2spki $KEYID
-.Pp
-.Nm gpg \-\-export\-secret\-key $KEYID | openpgp2ssh $KEYID
-.Sh DESCRIPTION
-.Nm
-takes an OpenPGP-formatted primary key and associated
-subkeys on standard input, and spits out the requested equivalent
-SSH-style (or PEM-encoded) key on standard output.
-.Pp
-If the data on standard input contains no subkeys, you can invoke
-.Nm
-without arguments. If the data on standard input contains multiple
-keys (e.g. a primary key and associated subkeys), you must specify a
-specific OpenPGP key identifier as the first argument to indicate
-which key to export. The key ID is normally the 40 hex digit OpenPGP
-fingerprint of the key or subkey desired, but
-.Nm
-will accept as few as the last 8 digits of the fingerprint as a key
-ID.
-.Pp
-If the input contains an OpenPGP RSA public key, it will be converted
-to the OpenSSH-style single-line keystring, prefixed with the key type
-(`ssh\-rsa'). This format is suitable (with minor alterations) for
-insertion into known_hosts files and authorized_keys files. If
-invoked as `openpgp2pem', a PEM-encoded public key will be emitted
-instead.
-.Pp
-If invoked as `openpgp2spki', a PEM-encoded subjectPublicKeyInfo (as
-defined in the X.509 standard) will be emitted instead.
-.Pp
-If the input contains an OpenPGP RSA secret key, it will be converted
-to the equivalent PEM-encoded private key.
-.Pp
-.Nm
-is part of the
-.Xr monkeysphere 7
-framework for providing a PKI for SSH.
-.Sh CAVEATS
-The keys produced by this process are stripped of all identifying
-information, including certifications, self-signatures, etc. This is
-intentional, since ssh attaches no inherent significance to these
-features.
-.Pp
-.Nm
-will produce output for any requested RSA key. This means, among
-other things, that it will happily export revoked keys, unverifiable
-keys, expired keys, etc. Make sure you do your own key validation
-before using this tool!
-.Sh EXAMPLES
-.Nm gpg \-\-export\-secret\-key $KEYID | openpgp2ssh $KEYID | ssh\-add \-c /dev/stdin
-.Pp
-This pushes the secret key into the active
-.Xr ssh\-agent 1 .
-Tools such as
-.Xr ssh 1
-which know how to talk to the
-.Xr ssh\-agent 1
-can now rely on the key.
-.Sh AUTHOR
-.Nm
-and this man page were written by Daniel Kahn Gillmor
-<dkg at fifthhorseman.net>.
-.Sh BUGS
-.Nm
-only works with RSA keys. DSA keys are the only other key type
-available in both OpenPGP and SSH, but they are currently unsupported
-by this utility.
-.Pp
-.Nm
-only accepts raw OpenPGP packets on standard input. It does not
-accept ASCII-armored input.
-.Nm
-Currently only exports into formats used by the OpenSSH.
-It should support other key output formats, such as those used by
-.Xr lsh 1
-and
-.Xr putty 1 .
-.Pp
-Secret key output is currently not passphrase-protected.
-.Pp
-.Nm
-currently cannot handle passphrase-protected secret keys on input.
-.Sh SEE ALSO
-.Xr pem2openpgp 1 ,
-.Xr monkeysphere 1 ,
-.Xr monkeysphere 7 ,
-.Xr ssh 1 ,
-.Xr monkeysphere-authentication 8 ,
-.Xr monkeysphere-host 8
=====================================
man/man1/pem2openpgp.1 deleted
=====================================
@@ -1,93 +0,0 @@
-.\" -*- nroff -*-
-.Dd $Mdocdate: Jan 22, 2019 $
-.Dt PEM2OPENPGP 1
-.Os
-.Sh NAME
-pem2openpgp
-.Nd translate PEM-encoded RSA keys to OpenPGP certificates
-.Sh SYNOPSIS
-.Nm pem2openpgp "$USERID" < mykey.pem | gpg \-\-import
-.Pp
-.Nm PEM2OPENPGP_EXPIRATION=$((86400 * $DAYS)) PEM2OPENPGP_USAGE_FLAGS=authenticate,certify pem2openpgp "$USERID" <mykey.pem
-.Sh DESCRIPTION
-.Nm
-is a low-level utility for transforming raw, PEM-encoded RSA secret
-keys into OpenPGP-formatted certificates. The generated certificates
-include the secret key material, so they should be handled carefully.
-.Pp
-It works as an element within a pipeline: feed it the raw key on
-stdin, supply the desired User ID as a command line argument. Note
-that you may need to quote the string to ensure that it is entirely in
-a single argument.
-.Pp
-Other choices about how to generate the new OpenPGP certificate are
-governed by environment variables.
-.Sh ENVIRONMENT
-The following environment variables influence the behavior of
-.Nm :
-.Pp
-.ti 3
-\fBPEM2OPENPGP_TIMESTAMP\fP controls the timestamp (measured in
-seconds since the UNIX epoch) indicated as the creation time (a.k.a
-"not valid before") of the generated certificate (self-signature) and
-the key itself. By default,
-.Nm
-uses the current time.
-.Pp
-.ti 3
-\fBPEM2OPENPGP_KEY_TIMESTAMP\fP controls the timestamp (measured in
-seconds since the UNIX epoch) indicated as the creation time of just
-the key itself (not the self-signature). By default,
-.Nm
-uses the value from PEM2OPENPGP_TIMESTAMP.
-.Pp
-.ti 3
-\fBPEM2OPENPGP_USAGE_FLAGS\fP should contain a comma-separated list of
-valid OpenPGP usage flags (see section 5.2.3.21 of RFC 4880 for what
-these mean). The available choices are: certify, sign, encrypt_comms,
-encrypt_storage, encrypt (this means both encrypt_comms and
-encrypt_storage), authenticate, split, shared. By default,
-.Nm
-only sets the certify flag.
-.Pp
-.ti 3
-\fBPEM2OPENPGP_EXPIRATION\fP sets an expiration (measured in seconds
-after the creation time of the key) in each self-signature packet. By
-default, no expiration subpacket is included.
-.Pp
-.ti 3
-\fBPEM2OPENPGP_NEWKEY\fP indicates that
-.Nm
-should ignore stdin, and instead generate a new key internally and
-build the certificate based on this new key. Set this variable to the
-number of bits for the new RSA key (e.g. 3072). By default (when this is
-unset),
-.Nm
-will read the key from stdin.
-.Sh AUTHOR
-.Nm
-and this man page were written by Daniel Kahn Gillmor
-<dkg at fifthhorseman.net>.
-.Sh BUGS
-Only handles RSA keys at the moment. It might be nice to handle DSA
-keys as well.
-.Pp
-Currently only creates certificates with a single User ID. Should be
-able to create certificates with multiple User IDs.
-.Pp
-Currently only accepts unencrypted RSA keys. It should be able to
-deal with passphrase-locked key material.
-.Pp
-Currently outputs OpenPGP certificates with cleartext secret key
-material. It would be good to be able to lock the output with a
-passphrase.
-.Pp
-If you find other bugs, please report them at
-https://labs.riseup.net/code/projects/show/monkeysphere
-.Sh SEE ALSO
-.Xr openpgp2ssh 1 ,
-.Xr monkeysphere 1 ,
-.Xr monkeysphere 7 ,
-.Xr ssh 1 ,
-.Xr monkeysphere\-host 8 ,
-.Xr monkeysphere\-authentication 8
=====================================
man/man7/monkeysphere.7
=====================================
@@ -82,8 +82,6 @@ Daniel Kahn Gillmor <dkg at fifthhorseman.net>
.BR monkeysphere (1),
.BR monkeysphere\-host (8),
.BR monkeysphere\-authentication (8),
-.BR openpgp2ssh (1),
-.BR pem2openpgp (1),
.BR gpg (1),
.BR https://tools.ietf.org/html/rfc4880,
.BR ssh (1),
=====================================
packaging/macports/Portfile
=====================================
@@ -56,8 +56,7 @@ post-build {
# fix perl shebang line to point to macports perl install
exec sed -i .tmp -e "s|^#!/usr/bin/perl -T$|#!/opt/local/bin/perl -T|" \
- ${worksrcpath}/src/share/keytrans \
- ${worksrcpath}/src/share/checkperms
+ ${worksrcpath}/src/share/keytrans
# remove leftover sed cruft
exec find ${worksrcpath} -name *.tmp -delete
=====================================
src/monkeysphere-host
=====================================
@@ -131,11 +131,15 @@ check_service_name() {
[ -n "$name" ] || \
failure "You must supply a service name to check"
- printf '%s' "$name" | perl -n -e '($str = $_) =~ s/\s//g ; exit !(lc($str) eq $_);' || \
+ [[ "$name" = "${name,,}" ]] || \
failure "Not a valid service name: '$name'
-Service names should be canonicalized to all lower-case,
-with no whitespace"
+Service names should be canonicalized to all lower-case."
+
+ [[ "$name" = "${name//$' \n\r\t'/}" ]] || \
+ failure "Not a valid service name: '$name'
+
+Service names should not contain whitespace."
[[ "$name" =~ ^[a-z0-9./:-]+$ ]] || \
failure "Not a valid service name: '$name'
=====================================
src/share/checkperms deleted
=====================================
@@ -1,111 +0,0 @@
-#!/usr/bin/perl -T
-
-# checkperms: ensure as best we can that a given file can only be
-# modified by the given user (or the superuser, naturally). This
-# means checking file ownership and permissions all the way back to
-# the root directory. Pass the file by its absolute path.
-
-# example invocation:
-
-# checkperms dkg /home/dkg/.monkeysphere/authorized_user_ids
-
-# return values: zero if we believe the file and path can only be
-# modified by the user. non-zero otherwise.
-
-# see StrictModes in sshd_config(5) (and its implementation in
-# OpenSSH's secure_filename() in auth.c) for the initial
-# inspiration/rationale for this code.
-
-# Author:
-# Daniel Kahn Gillmor <dkg at fifthhorseman.net>
-
-# Started on: 2009-07-31 11:10:16-0400
-
-# License: GPL v3 or later
-
-use strict;
-
-use Cwd qw(realpath); # found in debian in perl-base
-use File::stat; # found in debian in perl-modules
-use User::pwent; # found in debian in perl-modules
-use Fcntl qw(:mode); # for S_IS* functions (in perl-base)
-use File::Basename; # for dirname (in perl-modules)
-
-my $username = shift;
-my $path = shift;
-
-defined($username) or die "You must pass a username and an absolute path.\n";
-defined($path) or die "You must pass a username and an absolute path.\n";
-
-my $pw = getpwnam($username) or die "no such user $username\n";
-$path =~ m#^/# or die "path was not absolute (did not start with /)\n";
-
-sub mslog {
- my $level = shift;
-
- # FIXME: check and compare the log level
- if ($ENV{LOG_LEVEL} eq 'DEBUG') {
- my $format = shift;
- my $out = sprintf($format, @_);
-
- $out =~ s/^/$ENV{LOG_PREFIX}/ ;
-
- printf STDERR "%s", $out;
- }
-}
-
-## return undef if permissions are OK. otherwise return an error string
-sub permissions_ok {
- my $user = shift;
- my $path = shift;
-
- # if we can't even stat the path, the permissions are not ok:
- my $stat = lstat($path) or return "cannot stat '$path'";
-
- while (S_ISLNK($stat->mode)) {
- my $newpath = realpath($path) or return "cannot trace symlink '$path'";
- mslog('DEBUG', "tracing link %s to %s\n", $path, $newpath);
- $path = $newpath;
- $stat = lstat($path) or return "cannot stat '$path'";
- }
- mslog('DEBUG', "checking '%s'\n", $path);
-
- if (($stat->uid != $user->uid) &&
- ($stat->uid != 0)) {
- return sprintf("improper ownership on '%s': owner ID %d is neither %s (ID %d) nor the superuser",
- $path, $stat->uid, $user->name, $user->uid);
- }
-
- if ($stat->mode & S_IWGRP) {
- return sprintf("improper group writability on '%s'", $path);
- }
-
- if ($stat->mode & S_IWOTH) {
- return sprintf("improper other writability on '%s'", $path);
- }
-
- # see the rationalization in secure_filename() in auth.c in the
- # OpenSSH sources for an explanation of this bailout (see also
- # monkeysphere #675):
- if ($path eq $user->dir) {
- mslog('DEBUG', "stopping at %s's home directory '%s'\n", $user->name, $path);
- return undef;
- }
-
- my $nextlevel = dirname($path);
- if ($path eq $nextlevel) { # we bottom out at the root (/ in UNIX)
- return undef;
- }
- return permissions_ok($user, $nextlevel);
-}
-
-my $err = permissions_ok($pw, $path);
-
-if (defined($err)) {
- printf(STDERR "%s%s\n", $ENV{LOG_PREFIX}, $err);
-
- exit(1);
-} else {
- exit(0);
-}
-
=====================================
src/share/common
=====================================
@@ -417,6 +417,43 @@ touch_key_file_or_fail() {
fi
}
+check_perms() {
+ local username="$1"
+ local pathname="$2"
+
+ if [ -z "$username" ]; then
+ log error 'missing username'
+ return 1
+ fi
+ if [ -z "$pathname" ]; then
+ log error 'missing pathname'
+ return 1
+ fi
+ if ! [[ "$pathname" =~ ^/ ]]; then
+ log error 'pathname must be absolute (did not start with a /)'
+ return 1
+ fi
+
+ local homedir=$(realpath "$(get_homedir "$username")")
+ local cur=$(realpath "$pathname")
+ local -a paths=("$cur")
+ while [ "$cur" != "/" ] && [ "$cur" != "$homedir" ]; do
+ cur="${cur%/*}"
+ if [ -z "$cur" ]; then
+ cur=/
+ fi
+ paths+=("$cur")
+ done
+
+ log debug "$(printf 'checking permissions on %s\n' "${paths[@]}")"
+ local trouble=$(find "${paths[@]}" -maxdepth 0 \( \! \( -uid 0 -o -user "$username" \) \) -o -perm /go+w)
+ if [ -n "$trouble" ]; then
+ log error "$(printf 'bad ownership or permissions on file(s): %s' "${trouble//$'\n'/, }")"
+ return 1
+ fi
+}
+
+
# check that a file is properly owned, and that all it's parent
# directories are not group/other writable
check_key_file_permissions() {
@@ -431,7 +468,7 @@ check_key_file_permissions() {
return 0
fi
log debug "checking path permission '$path'..."
- "${SYSSHAREDIR}/checkperms" "$uname" "$path"
+ check_perms "$uname" "$path"
}
# return a list of all users on the system
=====================================
src/share/keytrans deleted
=====================================
@@ -1,1002 +0,0 @@
-#!/usr/bin/perl -T
-
-# keytrans: this is an RSA key translation utility; it is capable of
-# transforming RSA keys (both public keys and secret keys) between
-# several popular representations, including OpenPGP, PEM-encoded
-# PKCS#1 DER, and OpenSSH-style public key lines.
-
-# How it behaves depends on the name under which it is invoked. The
-# two implementations currently are: pem2openpgp and openpgp2ssh.
-
-
-
-# pem2openpgp: take a PEM-encoded RSA private-key on standard input, a
-# User ID as the first argument, and generate an OpenPGP secret key
-# and certificate from it.
-
-# WARNING: the secret key material *will* appear on stdout (albeit in
-# OpenPGP form) -- if you redirect stdout to a file, make sure the
-# permissions on that file are appropriately locked down!
-
-# Usage:
-
-# pem2openpgp 'ssh://'$(hostname -f) < /etc/ssh/ssh_host_rsa_key | gpg --import
-
-
-
-
-# openpgp2ssh: take a stream of OpenPGP packets containing public or
-# secret key material on standard input, and a Key ID (or fingerprint)
-# as the first argument. Find the matching key in the input stream,
-# and emit it on stdout in an OpenSSH-compatible format. If the input
-# key is an OpenPGP public key (either primary or subkey), the output
-# will be an OpenSSH single-line public key. If the input key is an
-# OpenPGP secret key, the output will be a PEM-encoded RSA key.
-
-# Example usage:
-
-# gpg --export-secret-subkeys --export-options export-reset-subkey-passwd $KEYID | \
-# openpgp2ssh $KEYID | ssh-add -
-
-
-# Authors:
-# Jameson Rollins <jrollins at finestructure.net>
-# Daniel Kahn Gillmor <dkg at fifthhorseman.net>
-
-# Started on: 2009-01-07 02:01:19-0500
-
-# License: GPL v3 or later (we may need to adjust this given that this
-# connects to OpenSSL via perl)
-
-use strict;
-use warnings;
-use File::Basename;
-use Crypt::OpenSSL::RSA;
-use Crypt::OpenSSL::Bignum;
-use Crypt::OpenSSL::Bignum::CTX;
-use Digest::SHA;
-use MIME::Base64;
-use POSIX;
-
-## make sure all length() and substr() calls use bytes only:
-use bytes;
-
-my $old_format_packet_lengths = { one => 0,
- two => 1,
- four => 2,
- indeterminate => 3,
-};
-
-# see RFC 4880 section 9.1 (ignoring deprecated algorithms for now)
-my $asym_algos = { rsa => 1,
- elgamal => 16,
- dsa => 17,
- };
-
-# see RFC 4880 section 9.2
-my $ciphers = { plaintext => 0,
- idea => 1,
- tripledes => 2,
- cast5 => 3,
- blowfish => 4,
- aes128 => 7,
- aes192 => 8,
- aes256 => 9,
- twofish => 10,
- };
-
-# see RFC 4880 section 9.3
-my $zips = { uncompressed => 0,
- zip => 1,
- zlib => 2,
- bzip2 => 3,
- };
-
-# see RFC 4880 section 9.4
-my $digests = { md5 => 1,
- sha1 => 2,
- ripemd160 => 3,
- sha256 => 8,
- sha384 => 9,
- sha512 => 10,
- sha224 => 11,
- };
-
-# see RFC 4880 section 5.2.3.21
-my $usage_flags = { certify => 0x01,
- sign => 0x02,
- encrypt_comms => 0x04,
- encrypt_storage => 0x08,
- encrypt => 0x0c, ## both comms and storage
- split => 0x10, # the private key is split via secret sharing
- authenticate => 0x20,
- shared => 0x80, # more than one person holds the entire private key
- };
-
-# see RFC 4880 section 4.3
-my $packet_types = { pubkey_enc_session => 1,
- sig => 2,
- symkey_enc_session => 3,
- onepass_sig => 4,
- seckey => 5,
- pubkey => 6,
- sec_subkey => 7,
- compressed_data => 8,
- symenc_data => 9,
- marker => 10,
- literal => 11,
- trust => 12,
- uid => 13,
- pub_subkey => 14,
- uat => 17,
- symenc_w_integrity => 18,
- mdc => 19,
- };
-
-# see RFC 4880 section 5.2.1
-my $sig_types = { binary_doc => 0x00,
- text_doc => 0x01,
- standalone => 0x02,
- generic_certification => 0x10,
- persona_certification => 0x11,
- casual_certification => 0x12,
- positive_certification => 0x13,
- subkey_binding => 0x18,
- primary_key_binding => 0x19,
- key_signature => 0x1f,
- key_revocation => 0x20,
- subkey_revocation => 0x28,
- certification_revocation => 0x30,
- timestamp => 0x40,
- thirdparty => 0x50,
- };
-
-
-# see RFC 4880 section 5.2.3.23
-my $revocation_reasons = { no_reason_specified => 0,
- key_superseded => 1,
- key_compromised => 2,
- key_retired => 3,
- user_id_no_longer_valid => 32,
- };
-
-# see RFC 4880 section 5.2.3.1
-my $subpacket_types = { sig_creation_time => 2,
- sig_expiration_time => 3,
- exportable => 4,
- trust_sig => 5,
- regex => 6,
- revocable => 7,
- key_expiration_time => 9,
- preferred_cipher => 11,
- revocation_key => 12,
- issuer => 16,
- notation => 20,
- preferred_digest => 21,
- preferred_compression => 22,
- keyserver_prefs => 23,
- preferred_keyserver => 24,
- primary_uid => 25,
- policy_uri => 26,
- usage_flags => 27,
- signers_uid => 28,
- revocation_reason => 29,
- features => 30,
- signature_target => 31,
- embedded_signature => 32,
- issuer_fpr => 33,
- };
-
-# bitstring (see RFC 4880 section 5.2.3.24)
-my $features = { mdc => 0x01
- };
-
-# bitstring (see RFC 4880 5.2.3.17)
-my $keyserver_prefs = { nomodify => 0x80
- };
-
-###### end lookup tables ######
-
-# FIXME: if we want to be able to interpret openpgp data as well as
-# produce it, we need to produce key/value-swapped lookup tables as well.
-
-
-########### Math/Utility Functions ##############
-
-
-# see the bottom of page 44 of RFC 4880 (https://tools.ietf.org/html/rfc4880#page-44)
-sub simple_checksum {
- my $bytes = shift;
-
- return unpack("%16C*",$bytes);
-}
-
-
-# calculate the multiplicative inverse of a mod b this is euclid's
-# extended algorithm. For more information see:
-# https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm the
-# arguments here should be Crypt::OpenSSL::Bignum objects. $a should
-# be the larger of the two values, and the two values should be
-# coprime.
-
-sub modular_multi_inverse {
- my $a = shift;
- my $b = shift;
-
-
- my $origdivisor = $b->copy();
-
- my $ctx = Crypt::OpenSSL::Bignum::CTX->new();
- my $x = Crypt::OpenSSL::Bignum->zero();
- my $y = Crypt::OpenSSL::Bignum->one();
- my $lastx = Crypt::OpenSSL::Bignum->one();
- my $lasty = Crypt::OpenSSL::Bignum->zero();
-
- my $finalquotient;
- my $finalremainder;
-
- while (! $b->is_zero()) {
- my ($quotient, $remainder) = $a->div($b, $ctx);
-
- $a = $b;
- $b = $remainder;
-
- my $temp = $x;
- $x = $lastx->sub($quotient->mul($x, $ctx));
- $lastx = $temp;
-
- $temp = $y;
- $y = $lasty->sub($quotient->mul($y, $ctx));
- $lasty = $temp;
- }
-
- if (!$a->is_one()) {
- die "did this math wrong.\n";
- }
-
- # let's make sure that we return a positive value because RFC 4880,
- # section 3.2 only allows unsigned values:
-
- ($finalquotient, $finalremainder) = $lastx->add($origdivisor)->div($origdivisor, $ctx);
-
- return $finalremainder;
-}
-
-
-############ OpenPGP formatting functions ############
-
-# make an old-style packet out of the given packet type and body.
-# old-style (see RFC 4880 section 4.2)
-sub make_packet {
- my $type = shift;
- my $body = shift;
- my $options = shift;
-
- my $len = length($body);
- my $pseudolen = $len;
-
- # if the caller wants to use at least N octets of packet length,
- # pretend that we're using that many.
- if (defined $options && defined $options->{'packet_length'}) {
- $pseudolen = 2**($options->{'packet_length'} * 8) - 1;
- }
- if ($pseudolen < $len) {
- $pseudolen = $len;
- }
-
- my $lenbytes;
- my $lencode;
-
- if ($pseudolen < 2**8) {
- $lenbytes = $old_format_packet_lengths->{one};
- $lencode = 'C';
- } elsif ($pseudolen < 2**16) {
- $lenbytes = $old_format_packet_lengths->{two};
- $lencode = 'n';
- } elsif ($pseudolen < 2**31) {
- ## not testing against full 32 bits because i don't want to deal
- ## with potential overflow.
- $lenbytes = $old_format_packet_lengths->{four};
- $lencode = 'N';
- } else {
- ## what the hell do we do here?
- $lenbytes = $old_format_packet_lengths->{indeterminate};
- $lencode = '';
- }
-
- return pack('C'.$lencode, 0x80 + ($type * 4) + $lenbytes, $len).
- $body;
-}
-
-
-# takes a Crypt::OpenSSL::Bignum, returns it formatted as OpenPGP MPI
-# (RFC 4880 section 3.2)
-sub mpi_pack {
- my $num = shift;
-
- my $val = $num->to_bin();
- my $mpilen = length($val)*8;
-
-# this is a kludgy way to get the number of significant bits in the
-# first byte:
- my $bitsinfirstbyte = length(sprintf("%b", ord($val)));
-
- $mpilen -= (8 - $bitsinfirstbyte);
-
- return pack('n', $mpilen).$val;
-}
-
-# takes a Crypt::OpenSSL::Bignum, returns an MPI packed in preparation
-# for an OpenSSH-style public key format. see:
-# https://marc.info/?l=openssh-unix-dev&m=121866301718839&w=2
-sub openssh_mpi_pack {
- my $num = shift;
-
- my $val = $num->to_bin();
- my $mpilen = length($val);
-
- my $ret = pack('N', $mpilen);
-
- # if the first bit of the leading byte is high, we should include a
- # 0 byte:
- if (ord($val) & 0x80) {
- $ret = pack('NC', $mpilen+1, 0);
- }
-
- return $ret.$val;
-}
-
-sub openssh_pubkey_pack {
- my $key = shift;
-
- my ($modulus, $exponent) = $key->get_key_parameters();
-
- return openssh_mpi_pack(Crypt::OpenSSL::Bignum->new_from_bin("ssh-rsa")).
- openssh_mpi_pack($exponent).
- openssh_mpi_pack($modulus);
-}
-
-# pull an OpenPGP-specified MPI off of a given stream, returning it as
-# a Crypt::OpenSSL::Bignum.
-sub read_mpi {
- my $instr = shift;
- my $readtally = shift;
-
- my $bitlen;
- read($instr, $bitlen, 2) or die "could not read MPI length.\n";
- $bitlen = unpack('n', $bitlen);
- $$readtally += 2;
-
- my $bytestoread = POSIX::floor(($bitlen + 7)/8);
- my $ret;
- read($instr, $ret, $bytestoread) or die "could not read MPI body.\n";
- $$readtally += $bytestoread;
- return Crypt::OpenSSL::Bignum->new_from_bin($ret);
-}
-
-
-# FIXME: genericize these to accept either RSA or DSA keys:
-sub make_rsa_pub_key_body {
- my $key = shift;
- my $key_timestamp = shift;
-
- my ($n, $e) = $key->get_key_parameters();
-
- return
- pack('CN', 4, $key_timestamp).
- pack('C', $asym_algos->{rsa}).
- mpi_pack($n).
- mpi_pack($e);
-}
-
-sub make_rsa_sec_key_body {
- my $key = shift;
- my $key_timestamp = shift;
-
- # we're not using $a and $b, but we need them to get to $c.
- my ($n, $e, $d, $p, $q) = $key->get_key_parameters();
-
- my $c3 = modular_multi_inverse($p, $q);
-
- my $secret_material = mpi_pack($d).
- mpi_pack($p).
- mpi_pack($q).
- mpi_pack($c3);
-
- # according to Crypt::OpenSSL::RSA, the closest value we can get out
- # of get_key_parameters is 1/q mod p; but according to sec 5.5.3 of
- # RFC 4880, we're actually looking for u, the multiplicative inverse
- # of p, mod q. This is why we're calculating the value directly
- # with modular_multi_inverse.
-
- return
- pack('CN', 4, $key_timestamp).
- pack('C', $asym_algos->{rsa}).
- mpi_pack($n).
- mpi_pack($e).
- pack('C', 0). # seckey material is not encrypted -- see RFC 4880 sec 5.5.3
- $secret_material.
- pack('n', simple_checksum($secret_material));
-}
-
-# expects an RSA key (public or private) and a timestamp
-sub fingerprint {
- my $key = shift;
- my $key_timestamp = shift;
-
- my $rsabody = make_rsa_pub_key_body($key, $key_timestamp);
-
- return Digest::SHA::sha1(pack('Cn', 0x99, length($rsabody)).$rsabody);
-}
-
-
-# FIXME: handle DSA keys as well!
-sub makeselfsig {
- my $rsa = shift;
- my $uid = shift;
- my $args = shift;
-
- # strong assertion of identity is the default (for a self-sig):
- if (! defined $args->{certification_type}) {
- $args->{certification_type} = $sig_types->{positive_certification};
- }
-
- if (! defined $args->{sig_timestamp}) {
- $args->{sig_timestamp} = time();
- }
- my $key_timestamp = $args->{key_timestamp} + 0;
-
- # generate and aggregate subpackets:
-
- # key usage flags:
- my $flags = 0;
- if (! defined $args->{usage_flags}) {
- $flags = $usage_flags->{certify};
- } else {
- my @ff = split(",", $args->{usage_flags});
- foreach my $f (@ff) {
- if (! defined $usage_flags->{$f}) {
- die "No such flag $f";
- }
- $flags |= $usage_flags->{$f};
- }
- }
- my $usage_subpacket = pack('CCC', 2, $subpacket_types->{usage_flags}, $flags);
-
- # how should we determine how far off to set the expiration date?
- # default is no expiration. Specify the timestamp in seconds from the
- # key creation.
- my $expiration_subpacket = '';
- if (defined $args->{expiration}) {
- my $expires_in = $args->{expiration} + 0;
- $expiration_subpacket = pack('CCN', 5, $subpacket_types->{key_expiration_time}, $expires_in);
- }
-
-
- # prefer AES-256, AES-192, AES-128, CAST5, 3DES:
- my $pref_sym_algos = pack('CCCCCCC', 6, $subpacket_types->{preferred_cipher},
- $ciphers->{aes256},
- $ciphers->{aes192},
- $ciphers->{aes128},
- $ciphers->{cast5},
- $ciphers->{tripledes}
- );
-
- # prefer SHA-512, SHA-384, SHA-256, SHA-224, RIPE-MD/160, SHA-1
- my $pref_hash_algos = pack('CCCCCCCC', 7, $subpacket_types->{preferred_digest},
- $digests->{sha512},
- $digests->{sha384},
- $digests->{sha256},
- $digests->{sha224},
- $digests->{ripemd160},
- $digests->{sha1}
- );
-
- # prefer ZLIB, BZip2, ZIP
- my $pref_zip_algos = pack('CCCCC', 4, $subpacket_types->{preferred_compression},
- $zips->{zlib},
- $zips->{bzip2},
- $zips->{zip}
- );
-
- # we support the MDC feature:
- my $feature_subpacket = pack('CCC', 2, $subpacket_types->{features},
- $features->{mdc});
-
- # keyserver preference: only owner modify (???):
- my $keyserver_pref = pack('CCC', 2, $subpacket_types->{keyserver_prefs},
- $keyserver_prefs->{nomodify});
-
-
- $args->{hashed_subpackets} =
- $usage_subpacket.
- $expiration_subpacket.
- $pref_sym_algos.
- $pref_hash_algos.
- $pref_zip_algos.
- $feature_subpacket.
- $keyserver_pref;
-
- return gensig($rsa, $uid, $args);
-}
-
-# FIXME: handle non-RSA keys
-
-# FIXME: this currently only makes self-sigs -- we should parameterize
-# it to make certifications over keys other than the issuer.
-sub gensig {
- my $rsa = shift;
- my $uid = shift;
- my $args = shift;
-
- # FIXME: allow signature creation using digests other than SHA256
- $rsa->use_sha256_hash();
-
- # see page 22 of RFC 4880 for why i think this is the right padding
- # choice to use:
- $rsa->use_pkcs1_padding();
-
- if (! $rsa->check_key()) {
- die "key does not check\n";
- }
-
- my $certtype = $args->{certification_type} + 0;
-
- my $version = pack('C', 4);
- my $sigtype = pack('C', $certtype);
- # RSA
- my $pubkey_algo = pack('C', $asym_algos->{rsa});
- # SHA256 FIXME: allow signature creation using digests other than SHA256
- my $hash_algo = pack('C', $digests->{sha256});
-
- # FIXME: i'm worried about generating a bazillion new OpenPGP
- # certificates from the same key, which could easily happen if you run
- # this script more than once against the same key (because the
- # timestamps will differ). How can we prevent this?
-
- # this argument (if set) overrides the current time, to
- # be able to create a standard key. If we read the key from a file
- # instead of stdin, should we use the creation time on the file?
- my $sig_timestamp = ($args->{sig_timestamp} + 0);
- my $key_timestamp = ($args->{key_timestamp} + 0);
-
- if ($key_timestamp > $sig_timestamp) {
- die "key timestamp must not be later than signature timestamp\n";
- }
- my $v4_fpr = fingerprint($rsa, $key_timestamp);
-
- my $creation_time_packet = pack('CCN', 5, $subpacket_types->{sig_creation_time}, $sig_timestamp);
-
- my $issuer_fpr_packet = pack('CCCa20', 22, $subpacket_types->{issuer_fpr}, 4, $v4_fpr);
-
- my $hashed_subs = $issuer_fpr_packet.$creation_time_packet.$args->{hashed_subpackets};
-
- my $subpacket_octets = pack('n', length($hashed_subs));
-
- my $sig_data_to_be_hashed =
- $version.
- $sigtype.
- $pubkey_algo.
- $hash_algo.
- $subpacket_octets.
- $hashed_subs;
-
- my $pubkey = make_rsa_pub_key_body($rsa, $key_timestamp);
-
- # this is for signing. it needs to be an old-style header with a
- # 2-packet octet count.
-
- my $key_data = make_packet($packet_types->{pubkey}, $pubkey, {'packet_length'=>2});
-
- # take the last 8 bytes of the fingerprint as the keyid:
- my $keyid = substr($v4_fpr, 20 - 8, 8);
-
- # the v4 signature trailer is:
-
- # version number, literal 0xff, and then a 4-byte count of the
- # signature data itself.
- my $trailer = pack('CCN', 4, 0xff, length($sig_data_to_be_hashed));
-
- my $uid_data =
- pack('CN', 0xb4, length($uid)).
- $uid;
-
- my $datatosign =
- $key_data.
- $uid_data.
- $sig_data_to_be_hashed.
- $trailer;
-
- # FIXME: handle signatures over digests other than SHA256:
- my $data_hash = Digest::SHA::sha256_hex($datatosign);
-
- my $issuer_packet = pack('CCa8', 9, $subpacket_types->{issuer}, $keyid);
-
- my $sig = Crypt::OpenSSL::Bignum->new_from_bin($rsa->sign($datatosign));
-
- my $sig_body =
- $sig_data_to_be_hashed.
- pack('n', length($issuer_packet)).
- $issuer_packet.
- pack('n', hex(substr($data_hash, 0, 4))).
- mpi_pack($sig);
-
- return make_packet($packet_types->{sig}, $sig_body);
-}
-
-# FIXME: switch to passing the whole packet as the arg, instead of the
-# input stream.
-
-# FIXME: think about native perl representation of the packets instead.
-
-# Put a user ID into the $data
-sub finduid {
- my $data = shift;
- my $instr = shift;
- my $tag = shift;
- my $packetlen = shift;
-
- my $dummy;
- ($tag == $packet_types->{uid}) or die "This should not be called on anything but a User ID packet\n";
-
- read($instr, $dummy, $packetlen);
- $data->{uid}->{$dummy} = {};
- $data->{current}->{uid} = $dummy;
-}
-
-
-# find signatures associated with the given fingerprint and user ID.
-sub findsig {
- my $data = shift;
- my $instr = shift;
- my $tag = shift;
- my $packetlen = shift;
-
- ($tag == $packet_types->{sig}) or die "No calling findsig on anything other than a signature packet.\n";
-
- my $dummy;
- my $readbytes = 0;
-
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not read in this packet.\n";
-
- if ((! defined $data->{key}) ||
- (! defined $data->{uid}) ||
- (! defined $data->{uid}->{$data->{target}->{uid}})) {
- # the user ID we are looking for has not been found yet.
- return;
- }
-
- if ( (!defined($data->{current_key_match})) ||
- (! $data->{current_key_match})) {
- # this is not the key in question.
- return;
- }
-
- # the current ID is not what we're looking for:
- return if ($data->{current}->{uid} ne $data->{target}->{uid});
-
- # just storing the raw signatures for the moment:
- push @{$data->{sigs}}, make_packet($packet_types->{sig}, $dummy);
- return;
-
-}
-
-# given an input stream and data, store the found key in data and
-# consume the rest of the stream corresponding to the packet.
-# data contains: (fpr: fingerprint to find, key: current best guess at key)
-sub findkey {
- my $data = shift;
- my $instr = shift;
- my $tag = shift;
- my $packetlen = shift;
-
- my $dummy;
- my $ver;
- my $readbytes = 0;
-
- read($instr, $ver, 1) or die "could not read key version\n";
- $readbytes += 1;
- $ver = ord($ver);
-
- if ($ver != 4) {
- printf(STDERR "We only work with version 4 keys. This key appears to be version %s.\n", $ver);
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
- return;
- }
-
- my $key_timestamp;
- read($instr, $key_timestamp, 4) or die "could not read key timestamp.\n";
- $readbytes += 4;
- $key_timestamp = unpack('N', $key_timestamp);
-
- my $algo;
- read($instr, $algo, 1) or die "could not read key algorithm.\n";
- $readbytes += 1;
- $algo = ord($algo);
- if ($algo != $asym_algos->{rsa}) {
- printf(STDERR "We only support RSA keys (this key used algorithm %d).\n", $algo);
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
- return;
- }
-
- ## we have an RSA key.
- my $modulus = read_mpi($instr, \$readbytes);
- my $exponent = read_mpi($instr, \$readbytes);
-
- my $pubkey = Crypt::OpenSSL::RSA->new_key_from_parameters($modulus, $exponent);
- my $foundfpr = fingerprint($pubkey, $key_timestamp);
-
- my $foundfprstr = Crypt::OpenSSL::Bignum->new_from_bin($foundfpr)->to_hex();
- # left-pad with 0's to bring up to full 40-char (160-bit) fingerprint:
- $foundfprstr = sprintf("%040s", $foundfprstr);
- $data->{current_key_match} = 0;
-
- # is this a match?
- if ((!defined($data->{target}->{fpr})) ||
- (substr($foundfprstr, -1 * length($data->{target}->{fpr})) eq $data->{target}->{fpr})) {
- if (defined($data->{key})) {
- die "Found two matching keys.\n";
- }
- $data->{key} = { 'rsa' => $pubkey,
- 'timestamp' => $key_timestamp };
- $data->{current_key_match} = 1;
- }
-
- if ($tag != $packet_types->{seckey} &&
- $tag != $packet_types->{sec_subkey}) {
- if ($readbytes < $packetlen) {
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
- }
- return;
- }
- if (!$data->{current_key_match}) {
- # we don't think the public part of this key matches
- if ($readbytes < $packetlen) {
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
- }
- return;
- }
-
- my $s2k;
- read($instr, $s2k, 1) or die "Could not read S2K octet.\n";
- $readbytes += 1;
- $s2k = ord($s2k);
- if ($s2k != 0) {
- printf(STDERR "We cannot handle encrypted secret keys. Skipping!\n") ;
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
- return;
- }
-
- # secret material is unencrypted
- # see https://tools.ietf.org/html/rfc4880#section-5.5.3
- my $d = read_mpi($instr, \$readbytes);
- my $p = read_mpi($instr, \$readbytes);
- my $q = read_mpi($instr, \$readbytes);
- my $u = read_mpi($instr, \$readbytes);
-
- my $checksum;
- read($instr, $checksum, 2) or die "Could not read checksum of secret key material.\n";
- $readbytes += 2;
- $checksum = unpack('n', $checksum);
-
- # FIXME: compare with the checksum! how? the data is
- # gone into the Crypt::OpenSSL::Bignum
-
- $data->{key}->{rsa} = Crypt::OpenSSL::RSA->new_key_from_parameters($modulus,
- $exponent,
- $d,
- $p,
- $q);
-
- $data->{key}->{rsa}->check_key() or die "Secret key is not a valid RSA key.\n";
-
- if ($readbytes < $packetlen) {
- read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
- }
-}
-
-sub openpgp2rsa {
- my $instr = shift;
- my $fpr = shift;
-
- if (defined $fpr) {
- if (length($fpr) < 8) {
- die "We need at least 8 hex digits of fingerprint.\n";
- }
- $fpr = uc($fpr);
- }
-
- my $data = { target => { fpr => $fpr,
- },
- };
- my $subs = { $packet_types->{pubkey} => \&findkey,
- $packet_types->{pub_subkey} => \&findkey,
- $packet_types->{seckey} => \&findkey,
- $packet_types->{sec_subkey} => \&findkey };
-
- packetwalk($instr, $subs, $data);
-
- return $data->{key}->{rsa};
-}
-
-sub findkeyfprs {
- my $data = shift;
- my $instr = shift;
- my $tag = shift;
- my $packetlen = shift;
-
- findkey($data, $instr, $tag, $packetlen);
- if (defined($data->{key})) {
- if (defined($data->{key}->{rsa}) && defined($data->{key}->{timestamp})) {
- $data->{keys}->{fingerprint($data->{key}->{rsa}, $data->{key}->{timestamp})} = $data->{key};
- } else {
- die "should have found some key here";
- }
- undef($data->{key});
- }
-};
-
-sub packetwalk {
- my $instr = shift;
- my $subs = shift;
- my $data = shift;
-
- my $packettag;
- my $dummy;
- my $tag;
-
- while (! eof($instr)) {
- read($instr, $packettag, 1);
- $packettag = ord($packettag);
-
- my $packetlen;
- if ( ! (0x80 & $packettag)) {
- die "This is not an OpenPGP packet\n";
- }
- if (0x40 & $packettag) {
- # this is a new-format packet.
- $tag = (0x3f & $packettag);
- my $nextlen = 0;
- read($instr, $nextlen, 1);
- $nextlen = ord($nextlen);
- if ($nextlen < 192) {
- $packetlen = $nextlen;
- } elsif ($nextlen < 224) {
- my $newoct;
- read($instr, $newoct, 1);
- $newoct = ord($newoct);
- $packetlen = (($nextlen - 192) << 8) + ($newoct) + 192;
- } elsif ($nextlen == 255) {
- read($instr, $nextlen, 4);
- $packetlen = unpack('N', $nextlen);
- } else {
- # packet length is undefined.
- }
- } else {
- # this is an old-format packet.
- my $lentype;
- $lentype = 0x03 & $packettag;
- $tag = ( 0x3c & $packettag ) >> 2;
- if ($lentype == 0) {
- read($instr, $packetlen, 1) or die "could not read packet length\n";
- $packetlen = unpack('C', $packetlen);
- } elsif ($lentype == 1) {
- read($instr, $packetlen, 2) or die "could not read packet length\n";
- $packetlen = unpack('n', $packetlen);
- } elsif ($lentype == 2) {
- read($instr, $packetlen, 4) or die "could not read packet length\n";
- $packetlen = unpack('N', $packetlen);
- } else {
- # packet length is undefined.
- }
- }
-
- if (! defined($packetlen)) {
- die "Undefined packet lengths are not supported.\n";
- }
-
- if (defined $subs->{$tag}) {
- $subs->{$tag}($data, $instr, $tag, $packetlen);
- } else {
- read($instr, $dummy, $packetlen) or die "Could not skip past this packet!\n";
- }
- }
-
- return $data->{key};
-}
-
-
-for (basename($0)) {
- if (/^pem2openpgp$/) {
- my $rsa;
- my $stdin;
-
- my $uid = shift;
- defined($uid) or die "You must specify a user ID string.\n";
-
- # FIXME: fail if there is no given user ID; or should we default to
- # hostname_long() from Sys::Hostname::Long ?
-
- if (defined $ENV{PEM2OPENPGP_NEWKEY}) {
- my $rsa_keysize = ($ENV{PEM2OPENPGP_NEWKEY} + 0);
- $rsa_keysize >= 2048 or die "Generating new RSA key: PEM2OPENPGP_NEWKEY should be at least 2048\n";
- $rsa = Crypt::OpenSSL::RSA->generate_key($rsa_keysize);
- } else {
- $stdin = do {
- local $/; # slurp!
- <STDIN>;
- };
-
- $rsa = Crypt::OpenSSL::RSA->new_private_key($stdin);
- }
-
- my $key_timestamp = $ENV{PEM2OPENPGP_KEY_TIMESTAMP};
- my $sig_timestamp = $ENV{PEM2OPENPGP_TIMESTAMP};
- $sig_timestamp = time() if (!defined $sig_timestamp);
- $key_timestamp = $sig_timestamp if (!defined $key_timestamp);
-
- print
- make_packet($packet_types->{seckey}, make_rsa_sec_key_body($rsa, $key_timestamp)).
- make_packet($packet_types->{uid}, $uid).
- makeselfsig($rsa,
- $uid,
- { sig_timestamp => $sig_timestamp,
- key_timestamp => $key_timestamp,
- expiration => $ENV{PEM2OPENPGP_EXPIRATION},
- usage_flags => $ENV{PEM2OPENPGP_USAGE_FLAGS},
- }
- );
- }
- elsif (/^openpgp2ssh$/) {
- my $fpr = shift;
- my $instream;
- open($instream,'-');
- binmode($instream, ":bytes");
- my $key = openpgp2rsa($instream, $fpr);
- if (defined($key)) {
- if ($key->is_private()) {
- print $key->get_private_key_string();
- } else {
- print "ssh-rsa ".encode_base64(openssh_pubkey_pack($key), '')."\n";
- }
- } else {
- die "No matching key found.\n";
- }
- }
- elsif (/^openpgp2pem$/) {
- my $fpr = shift;
- my $instream;
- open($instream,'-');
- binmode($instream, ":bytes");
- my $key = openpgp2rsa($instream, $fpr);
- if (defined($key)) {
- if ($key->is_private()) {
- print $key->get_private_key_string();
- } else {
- print $key->get_public_key_string();
- }
- } else {
- die "No matching key found.\n";
- }
- }
- elsif (/^openpgp2spki$/) {
- my $fpr = shift;
- my $instream;
- open($instream,'-');
- binmode($instream, ":bytes");
- my $key = openpgp2rsa($instream, $fpr);
- if (defined($key)) {
- print $key->get_public_key_x509_string();
- } else {
- die "No matching key found.\n";
- }
- }
- elsif (/^keytrans$/) {
- # subcommands when keytrans is invoked directly are UNSUPPORTED,
- # UNDOCUMENTED, and WILL NOT BE MAINTAINED.
- die "Unrecognized subcommand. keytrans subcommands are not a stable interface!\n";
- }
- else {
- die "Unrecognized keytrans call.\n";
- }
-}
=====================================
src/share/ma/setup
=====================================
@@ -67,7 +67,7 @@ EOF
if [ -z "$CORE_FPR" ] ; then
log info "setting up Monkeysphere authentication trust core..."
- local CORE_UID=$(printf "Monkeysphere authentication trust core UID (random string: %s)" $(dd if=/dev/urandom bs=21 count=1 2>/dev/null | perl -MMIME::Base64 -ne 'print encode_base64($_)'))
+ local CORE_UID=$(printf "Monkeysphere authentication trust core UID (random string: %s)" $(dd if=/dev/urandom bs=21 count=1 2>/dev/null | base64))
printf "generating monkeysphere authentication trust core RSA key:\nsize: %d bits\nuid: '%s'\n" "$CORE_KEYLENGTH" "$CORE_UID" | log debug
gpg_core --pinentry-mode=loopback --passphrase '' --quick-generate-key "$CORE_UID" "rsa$CORE_KEYLENGTH" cert \
=====================================
tests/basic
=====================================
@@ -165,7 +165,7 @@ export DISPLAY=monkeys
## we cannot do proper directory permissions checking if the current
## working directory has unsatisfactory permissions:
-if "$MONKEYSPHERE_SYSSHAREDIR"/checkperms $(whoami) "$TEMPDIR"; then
+if bash -c "$(printf 'source %q/common && check_perms %q %q' "$MONKEYSPHERE_SYSSHAREDIR" "$(whoami)" "$TEMPDIR")"; then
echo "Permissions on temporary directory '$TEMPDIR' are OK for permissions checks."
TEMPDIR_PERMISSIONS_SAFE=yes
else
=====================================
tests/keytrans deleted
=====================================
@@ -1,178 +0,0 @@
-#!/usr/bin/env bash
-
-# Tests to ensure that the monkeysphere is working
-
-# Authors:
-# Daniel Kahn Gillmor <dkg at fifthhorseman.net>
-# Jameson Rollins <jrollins at fifthhorseman.net>
-# Micah Anderson <micah at riseup.net>
-#
-# Copyright: 2008-2019
-# License: GPL v3 or later
-
-# these tests should all be able to run as a non-privileged user.
-
-# all subcommands in this script should complete without failure:
-set -e
-# piped commands should return the code of the first non-zero return
-set -o pipefail
-
-declare -a child_procs=($(ps -o pid h --ppid $$))
-if [ "${#child_procs[@]}" -gt 1 ]; then
- printf 'found %d pre-existing child processes: %s\n' "${#child_procs[@]}" "${child_procs[*]}"
- printf "spawning my own subprocess to avoid https://bugs.debian.org/920038...\n"
- "$0" "$@"
- exit
-fi
-
-# make sure the TESTDIR is an absolute path, not a relative one.
-export TESTDIR=$(cd $(dirname "$0") && pwd)
-
-source "$TESTDIR"/common
-
-perl -MCrypt::OpenSSL::RSA -e 1 2>/dev/null || { echo "You must have the perl module Crypt::OpenSSL::RSA installed to run this test.
-On debian-derived systems, you can set this up with:
- apt-get install libcrypt-openssl-rsa-perl" ; exit 1; }
-
-perl -MDigest::SHA -e 1 2>/dev/null || { echo "You must have the perl module Digest::SHA installed to run this test.
-On debian-derived systems, you can set this up with:
- apt-get install libdigest-sha1-perl" ; exit 1; }
-
-
-######################################################################
-### SETUP VARIABLES
-
-## set up some variables to ensure that we're operating strictly in
-## the tests, not system-wide:
-
-mkdir -p "$TESTDIR"/tmp
-TEMPDIR=$(mktemp -d "${TMPDIR:-$TESTDIR/tmp}/ms.XXX")
-
-if [ -z "$MONKEYSPHERE_TEST_USE_SYSTEM" ] ; then
- mkdir "$TEMPDIR"/bin
- ln -s "$TESTDIR"/../src/share/keytrans "$TEMPDIR"/bin/openpgp2ssh
- ln -s "$TESTDIR"/../src/share/keytrans "$TEMPDIR"/bin/pem2openpgp
- ln -s "$TESTDIR"/../src/share/keytrans "$TEMPDIR"/bin/keytrans
-
- # Use the local copy of executables first, instead of system ones.
- # This should help us test without installing.
- export PATH="$TEMPDIR"/bin:"$PATH"
-else
- export PATH=/usr/share/monkeysphere:"$PATH"
-fi
-
-## setup trap
-trap failed_cleanup EXIT
-
-######################################################################
-### TEST KEYTRANS
-
-echo "##################################################"
-echo "### generating openpgp key..."
-export GNUPGHOME="$TEMPDIR"
-chmod 700 "$TEMPDIR"
-
-
-# create the key with the same preferences that monkeysphere uses.
-cat > "$TEMPDIR"/gpg.conf <<EOF
-default-preference-list SHA512 SHA384 SHA256 SHA224 RIPEMD160 SHA1 ZLIB BZIP2 ZIP AES256 AES192 AES CAST5 3DES
-cert-digest-algo SHA256
-list-options show-uid-validity,show-unusable-uids
-fixed-list-mode
-EOF
-
-cat > "$TEMPDIR"/gpg-agent.conf <<EOF
-pinentry-program $TESTDIR/phony-pinentry-nopass
-EOF
-
-# generate a key
-gpg --batch --$(get_gpg_prng_arg) --gen-key <<EOF
-Key-Type: RSA
-Key-Length: 3072
-Key-Usage: sign
-Name-Real: testtest
-Expire-Date: 0
-
-%no-ask-passphrase
-%no-protection
-%commit
-%echo done
-EOF
-
-echo "##################################################"
-echo "### retrieving key timestamp..."
-timestamp=$(gpg --list-key --with-colons | \
- grep ^pub: | cut -d: -f6)
-
-echo "##################################################"
-echo "### exporting key to ssh file..."
-gpg --export-secret-keys | openpgp2ssh > \
- "$TEMPDIR"/test.pem
-
-gpg --export-secret-keys > "$TEMPDIR"/secret.key
-
-PEM2OPENPGP_USAGE_FLAGS=sign,certify \
-PEM2OPENPGP_TIMESTAMP="$timestamp" pem2openpgp testtest \
- < "$TEMPDIR"/test.pem > "$TEMPDIR"/converted.secret.key
-
-echo "##################################################"
-echo "### reconvert key, and compare to key in gpg keyring..."
-diff -u \
- <(gpg --list-packets < "$TEMPDIR"/secret.key) \
- <(gpg --list-packets < "$TEMPDIR"/converted.secret.key)
-
-diff -u \
- <(hd "$TEMPDIR"/secret.key) \
- <(hd "$TEMPDIR"/converted.secret.key)
-
-KEYFPR=$(gpg --fingerprint --with-colons --list-keys | awk -F: '/^fpr:/{ if (ok) { print $10 } ; ok=0 } /^pub:/{ ok=1 }')
-KEYID=$(printf "%s" "$KEYFPR" | cut -b25-40)
-
-echo "conversions look good!"
-
-echo "Now working with key $KEYID at time $timestamp"
-
-gpg --check-trustdb
-gpg --list-keys
-
-
-echo "##################################################"
-echo "### test working with two primary keys ... "
-
-ssh-keygen -m PEM -t rsa -b 3072 -N '' -f "$TEMPDIR"/newkey
-
-PEM2OPENPGP_USAGE_FLAGS=authenticate,certify \
-PEM2OPENPGP_TIMESTAMP="$(( $timestamp + 1 ))" pem2openpgp fubar \
- < "$TEMPDIR"/newkey > "$TEMPDIR"/newkey.gpg
-
-NEWKEYFPR=$(< "$TEMPDIR"/newkey.gpg gpg --with-colons --import-options import-show --dry-run --import | awk -F: '/^fpr:/{ print $10 }' )
-NEWKEYID=$( printf "%s" "$NEWKEYFPR" | cut -b25-40)
-
-< "$TEMPDIR"/newkey.gpg gpg --import
-
-gpg --batch --no-tty --faked-system-time "$timestamp" --quick-add-uid "$KEYID" baz
-
-cat >"$TEMPDIR"/expectedout <<EOF
-pub:u:3072:1:$KEYID:$timestamp:::u:::scSC
-uid:u::::$timestamp::8200BD0425CC70C7D698DF3FE412044EAAB83F94::testtest
-sig:!::1:$KEYID:$timestamp::::testtest:13x::$KEYFPR:::8
-uid:u::::$timestamp::EDDC32D783E7F4C7B6982D9AE5DC4A61000648BA::baz
-sig:!::1:$KEYID:$timestamp::::testtest:13x::$KEYFPR:::8
-pub:-:3072:1:$NEWKEYID:$(($timestamp + 1)):::-:::caCA
-uid:-::::$(($timestamp + 1))::A0D708F51CC257DEFC01AEDE1E0A5F329DFD8F16::fubar
-sig:!::1:$NEWKEYID:$(($timestamp + 1))::::fubar:13x::$NEWKEYFPR:::8
-EOF
-
-echo "test: diff expected gpg list output"
-diff -u "$TEMPDIR"/expectedout <(gpg --check-sigs --with-colons | grep -vE '^(tru|fpr):' | cut -d: -f1-16 | sed 's/:*$//')
-
-## FIXME: addtest: not testing subkeys at the moment.
-
-
-trap - EXIT
-
-echo "##################################################"
-echo " Monkeysphere keytrans test completed successfully!"
-echo "##################################################"
-
-cleanup
View it on GitLab: https://salsa.debian.org/pkg-privacy-team/monkeysphere/compare/ed6dd03bb8db1316698eeb7106257ef22dc50235...27fa1b3009373d0f78f2519567b6db79c4104982
--
View it on GitLab: https://salsa.debian.org/pkg-privacy-team/monkeysphere/compare/ed6dd03bb8db1316698eeb7106257ef22dc50235...27fa1b3009373d0f78f2519567b6db79c4104982
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-privacy-commits/attachments/20190517/32d026bb/attachment-0001.html>
More information about the Pkg-privacy-commits
mailing list