From bb3e880c0198cf96213beaa7b640f06c76db9730 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Tue, 17 Feb 2015 12:44:33 +0100 Subject: [PATCH] Add SSH KDF CAVS test driver for future FIPS validation (#1193045) --- openssh-6.7p1-fips.patch | 2 +- openssh-6.7p1-kdf-cavs.patch | 610 +++++++++++++++++++++++++++++++++++ openssh.spec | 5 + 3 files changed, 616 insertions(+), 1 deletion(-) create mode 100644 openssh-6.7p1-kdf-cavs.patch diff --git a/openssh-6.7p1-fips.patch b/openssh-6.7p1-fips.patch index 3d9afe7..984a038 100644 --- a/openssh-6.7p1-fips.patch +++ b/openssh-6.7p1-fips.patch @@ -35,7 +35,7 @@ index 9311e16..1eb2b45 100644 ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) @@ -197,7 +197,7 @@ ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o - $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) + $(LD) -o $@ ssh-cavs.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o - $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) diff --git a/openssh-6.7p1-kdf-cavs.patch b/openssh-6.7p1-kdf-cavs.patch new file mode 100644 index 0000000..19e1b53 --- /dev/null +++ b/openssh-6.7p1-kdf-cavs.patch @@ -0,0 +1,610 @@ +diff --git a/Makefile.in b/Makefile.in +index 1eb2b45..cfa89a1 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -29,6 +29,7 @@ SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper + SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper + SSH_KEYCAT=$(libexecdir)/ssh-keycat + CTR_CAVSTEST=$(libexecdir)/ctr-cavstest ++SSH_CAVS=$(libexecdir)/ssh-cavs + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ +@@ -67,7 +68,7 @@ EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ + INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ + +-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) ++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) ssh-cavs$(EXEEXT) + + LIBOPENSSH_OBJS=\ + ssherr.o \ +@@ -196,6 +196,9 @@ ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o + ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o + $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) + ++ssh-cavs$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-cavs.o roaming_dummy.o ++ $(LD) -o $@ ssh-cavs.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o + $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + +@@ -320,6 +321,8 @@ install-files: + fi + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ctr-cavstest$(EXEEXT) $(DESTDIR)$(libexecdir)/ctr-cavstest$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-cavs$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-cavs$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-cavs_driver.pl $(DESTDIR)$(libexecdir)/ssh-cavs_driver.pl + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 +diff --git a/ssh-cavs.c b/ssh-cavs.c +new file mode 100644 +index 0000000..928ff80 +--- /dev/null ++++ b/ssh-cavs.c +@@ -0,0 +1,374 @@ ++/* ++ * Copyright (C) 2015, Stephan Mueller ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU General Public License, in which case the provisions of the GPL2 ++ * are required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "includes.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "xmalloc.h" ++#include "buffer.h" ++#include "key.h" ++#include "cipher.h" ++#include "kex.h" ++ ++static int bin_char(unsigned char hex) ++{ ++ if (48 <= hex && 57 >= hex) ++ return (hex - 48); ++ if (65 <= hex && 70 >= hex) ++ return (hex - 55); ++ if (97 <= hex && 102 >= hex) ++ return (hex - 87); ++ return 0; ++} ++ ++/* ++ * Convert hex representation into binary string ++ * @hex input buffer with hex representation ++ * @hexlen length of hex ++ * @bin output buffer with binary data ++ * @binlen length of already allocated bin buffer (should be at least ++ * half of hexlen -- if not, only a fraction of hexlen is converted) ++ */ ++static void hex2bin(const char *hex, size_t hexlen, ++ unsigned char *bin, size_t binlen) ++{ ++ size_t i = 0; ++ size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen; ++ ++ for (i = 0; i < chars; i++) { ++ bin[i] = bin_char(hex[(i*2)]) << 4; ++ bin[i] |= bin_char(hex[((i*2)+1)]); ++ } ++} ++ ++/* ++ * Allocate sufficient space for binary representation of hex ++ * and convert hex into bin ++ * ++ * Caller must free bin ++ * @hex input buffer with hex representation ++ * @hexlen length of hex ++ * @bin return value holding the pointer to the newly allocated buffer ++ * @binlen return value holding the allocated size of bin ++ * ++ * return: 0 on success, !0 otherwise ++ */ ++static int hex2bin_alloc(const char *hex, size_t hexlen, ++ unsigned char **bin, size_t *binlen) ++{ ++ unsigned char *out = NULL; ++ size_t outlen = 0; ++ ++ if (!hexlen) ++ return -EINVAL; ++ ++ outlen = (hexlen + 1) / 2; ++ ++ out = calloc(1, outlen); ++ if (!out) ++ return -errno; ++ ++ hex2bin(hex, hexlen, out, outlen); ++ *bin = out; ++ *binlen = outlen; ++ return 0; ++} ++ ++static char hex_char_map_l[] = { '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; ++static char hex_char_map_u[] = { '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; ++static char hex_char(unsigned int bin, int u) ++{ ++ if (bin < sizeof(hex_char_map_l)) ++ return (u) ? hex_char_map_u[bin] : hex_char_map_l[bin]; ++ return 'X'; ++} ++ ++/* ++ * Convert binary string into hex representation ++ * @bin input buffer with binary data ++ * @binlen length of bin ++ * @hex output buffer to store hex data ++ * @hexlen length of already allocated hex buffer (should be at least ++ * twice binlen -- if not, only a fraction of binlen is converted) ++ * @u case of hex characters (0=>lower case, 1=>upper case) ++ */ ++static void bin2hex(const unsigned char *bin, size_t binlen, ++ char *hex, size_t hexlen, int u) ++{ ++ size_t i = 0; ++ size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen; ++ ++ for (i = 0; i < chars; i++) { ++ hex[(i*2)] = hex_char((bin[i] >> 4), u); ++ hex[((i*2)+1)] = hex_char((bin[i] & 0x0f), u); ++ } ++} ++ ++struct kdf_cavs { ++ unsigned char *K; ++ size_t Klen; ++ unsigned char *H; ++ size_t Hlen; ++ unsigned char *session_id; ++ size_t session_id_len; ++ ++ unsigned int iv_len; ++ unsigned int ek_len; ++ unsigned int ik_len; ++}; ++ ++static int sshkdf_cavs(struct kdf_cavs *test) ++{ ++ int ret = 0; ++ Kex kex; ++ BIGNUM *Kbn = NULL; ++ int mode = 0; ++ Newkeys *ctoskeys; ++ Newkeys *stockeys; ++ ++#define HEXOUTLEN 500 ++ char hex[HEXOUTLEN]; ++ ++ memset(&kex, 0, sizeof(Kex)); ++ ++ Kbn = BN_new(); ++ BN_bin2bn(test->K, test->Klen, Kbn); ++ if (!Kbn) { ++ printf("cannot convert K into BIGNUM\n"); ++ ret = 1; ++ goto out; ++ } ++ ++ kex.session_id = test->session_id; ++ kex.session_id_len = test->session_id_len; ++ ++ /* setup kex */ ++ ++ /* select the right hash based on struct ssh_digest digests */ ++ switch (test->ik_len) { ++ case 20: ++ kex.hash_alg = 2; ++ break; ++ case 32: ++ kex.hash_alg = 3; ++ break; ++ case 48: ++ kex.hash_alg = 4; ++ break; ++ case 64: ++ kex.hash_alg = 5; ++ break; ++ default: ++ printf("Wrong hash type %u\n", test->ik_len); ++ ret = 1; ++ goto out; ++ } ++ ++ /* implement choose_enc */ ++ for (mode = 0; mode < 2; mode++) { ++ kex.newkeys[mode] = calloc(1, sizeof(Newkeys)); ++ if (!kex.newkeys[mode]) { ++ printf("allocation of newkeys failed\n"); ++ ret = 1; ++ goto out; ++ } ++ kex.newkeys[mode]->enc.iv_len = test->iv_len; ++ kex.newkeys[mode]->enc.key_len = test->ek_len; ++ kex.newkeys[mode]->enc.block_size = (test->iv_len == 64) ? 8 : 16; ++ kex.newkeys[mode]->mac.key_len = test->ik_len; ++ } ++ ++ /* implement kex_choose_conf */ ++ kex.we_need = kex.newkeys[0]->enc.key_len; ++ if (kex.we_need < kex.newkeys[0]->enc.block_size) ++ kex.we_need = kex.newkeys[0]->enc.block_size; ++ if (kex.we_need < kex.newkeys[0]->enc.iv_len) ++ kex.we_need = kex.newkeys[0]->enc.iv_len; ++ if (kex.we_need < kex.newkeys[0]->mac.key_len) ++ kex.we_need = kex.newkeys[0]->mac.key_len; ++ ++ /* MODE_OUT (1) -> server to client ++ * MODE_IN (0) -> client to server */ ++ kex.server = 1; ++ ++ /* do it */ ++ kex_derive_keys_bn(&kex, test->H, test->Hlen, Kbn); ++ ++ ctoskeys = kex_get_newkeys(0); ++ stockeys = kex_get_newkeys(1); ++ ++ /* get data */ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(ctoskeys->enc.iv, (size_t)ctoskeys->enc.iv_len, ++ hex, HEXOUTLEN, 0); ++ printf("Initial IV (client to server) = %s\n", hex); ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(stockeys->enc.iv, (size_t)stockeys->enc.iv_len, ++ hex, HEXOUTLEN, 0); ++ printf("Initial IV (server to client) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(ctoskeys->enc.key, (size_t)ctoskeys->enc.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Encryption key (client to server) = %s\n", hex); ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(stockeys->enc.key, (size_t)stockeys->enc.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Encryption key (server to client) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(ctoskeys->mac.key, (size_t)ctoskeys->mac.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Integrity key (client to server) = %s\n", hex); ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(stockeys->mac.key, (size_t)stockeys->mac.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Integrity key (server to client) = %s\n", hex); ++ ++ free(ctoskeys); ++ free(stockeys); ++ ++out: ++ if (Kbn) ++ BN_free(Kbn); ++ if (kex.newkeys[0]) ++ free(kex.newkeys[0]); ++ if (kex.newkeys[1]) ++ free(kex.newkeys[1]); ++ return ret; ++} ++ ++static void usage(void) ++{ ++ fprintf(stderr, "\nOpenSSH KDF CAVS Test\n\n"); ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, "\t-K\tShared secret string\n"); ++ fprintf(stderr, "\t-H\tHash string\n"); ++ fprintf(stderr, "\t-s\tSession ID string\n"); ++ fprintf(stderr, "\t-i\tIV length to be generated\n"); ++ fprintf(stderr, "\t-e\tEncryption key length to be generated\n"); ++ fprintf(stderr, "\t-m\tMAC key length to be generated\n"); ++} ++ ++/* ++ * Test command example: ++ * ./ssh-cavs -K 0055d50f2d163cc07cd8a93cc7c3430c30ce786b572c01ad29fec7597000cf8618d664e2ec3dcbc8bb7a1a7eb7ef67f61cdaf291625da879186ac0a5cb27af571b59612d6a6e0627344d846271959fda61c78354aa498773d59762f8ca2d0215ec590d8633de921f920d41e47b3de6ab9a3d0869e1c826d0e4adebf8e3fb646a15dea20a410b44e969f4b791ed6a67f13f1b74234004d5fa5e87eff7abc32d49bbdf44d7b0107e8f10609233b7e2b7eff74a4daf25641de7553975dac6ac1e5117df6f6dbaa1c263d23a6c3e5a3d7d49ae8a828c1e333ac3f85fbbf57b5c1a45be45e43a7be1a4707eac779b8285522d1f531fe23f890fd38a004339932b93eda4 -H d3ab91a850febb417a25d892ec48ed5952c7a5de -s d3ab91a850febb417a25d892ec48ed5952c7a5de -i 8 -e 24 -m 20 ++ * ++ * Initial IV (client to server) = 4bb320d1679dfd3a ++ * Initial IV (server to client) = 43dea6fdf263a308 ++ * Encryption key (client to server) = 13048cc600b9d3cf9095aa6cf8e2ff9cf1c54ca0520c89ed ++ * Encryption key (server to client) = 1e483c5134e901aa11fc4e0a524e7ec7b75556148a222bb0 ++ * Integrity key (client to server) = ecef63a092b0dcc585bdc757e01b2740af57d640 ++ * Integrity key (server to client) = 7424b05f3c44a72b4ebd281fb71f9cbe7b64d479 ++ */ ++int main(int argc, char *argv[]) ++{ ++ struct kdf_cavs test; ++ int ret = 1; ++ int opt = 0; ++ ++ memset(&test, 0, sizeof(struct kdf_cavs)); ++ while((opt = getopt(argc, argv, "K:H:s:i:e:m:")) != -1) ++ { ++ size_t len = 0; ++ switch(opt) ++ { ++ /* ++ * CAVS K is MPINT ++ * we want a hex (i.e. the caller must ensure the ++ * following transformations already happened): ++ * 1. cut off first four bytes ++ * 2. if most significant bit of value is ++ * 1, prepend 0 byte ++ */ ++ case 'K': ++ len = strlen(optarg); ++ ret = hex2bin_alloc(optarg, len, ++ &test.K, &test.Klen); ++ if (ret) ++ goto out; ++ break; ++ case 'H': ++ len = strlen(optarg); ++ ret = hex2bin_alloc(optarg, len, ++ &test.H, &test.Hlen); ++ if (ret) ++ goto out; ++ break; ++ case 's': ++ len = strlen(optarg); ++ ret = hex2bin_alloc(optarg, len, ++ &test.session_id, ++ &test.session_id_len); ++ if (ret) ++ goto out; ++ break; ++ case 'i': ++ test.iv_len = strtoul(optarg, NULL, 10); ++ break; ++ case 'e': ++ test.ek_len = strtoul(optarg, NULL, 10); ++ break; ++ case 'm': ++ test.ik_len = strtoul(optarg, NULL, 10); ++ break; ++ default: ++ usage(); ++ goto out; ++ } ++ } ++ ++ ret = sshkdf_cavs(&test); ++ ++out: ++ if (test.session_id) ++ free(test.session_id); ++ if (test.K) ++ free(test.K); ++ if (test.H) ++ free(test.H); ++ return ret; ++ ++} +diff --git a/ssh-cavs_driver.pl b/ssh-cavs_driver.pl +new file mode 100644 +index 0000000..6ed8f26 +--- /dev/null ++++ b/ssh-cavs_driver.pl +@@ -0,0 +1,184 @@ ++#!/usr/bin/env perl ++# ++# CAVS test driver for OpenSSH ++# ++# Copyright (C) 2015, Stephan Mueller ++# ++# Permission is hereby granted, free of charge, to any person obtaining a copy ++# of this software and associated documentation files (the "Software"), to deal ++# in the Software without restriction, including without limitation the rights ++# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++# copies of the Software, and to permit persons to whom the Software is ++# furnished to do so, subject to the following conditions: ++# ++# The above copyright notice and this permission notice shall be included in ++# all copies or substantial portions of the Software. ++# ++# NO WARRANTY ++# ++# BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++# FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++# OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++# PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++# OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++# TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++# PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++# REPAIR OR CORRECTION. ++# ++# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++# REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++# INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++# OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++# TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++# YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++# PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++# POSSIBILITY OF SUCH DAMAGES. ++# ++use strict; ++use warnings; ++use IPC::Open2; ++ ++# Executing a program by feeding STDIN and retrieving ++# STDOUT ++# $1: data string to be piped to the app on STDIN ++# rest: program and args ++# returns: STDOUT of program as string ++sub pipe_through_program($@) { ++ my $in = shift; ++ my @args = @_; ++ ++ my ($CO, $CI); ++ my $pid = open2($CO, $CI, @args); ++ ++ my $out = ""; ++ my $len = length($in); ++ my $first = 1; ++ while (1) { ++ my $rin = ""; ++ my $win = ""; ++ # Output of prog is FD that we read ++ vec($rin,fileno($CO),1) = 1; ++ # Input of prog is FD that we write ++ # check for $first is needed because we can have NULL input ++ # that is to be written to the app ++ if ( $len > 0 || $first) { ++ (vec($win,fileno($CI),1) = 1); ++ $first=0; ++ } ++ # Let us wait for 100ms ++ my $nfound = select(my $rout=$rin, my $wout=$win, undef, 0.1); ++ if ( $wout ) { ++ my $written = syswrite($CI, $in, $len); ++ die "broken pipe" if !defined $written; ++ $len -= $written; ++ substr($in, 0, $written) = ""; ++ if ($len <= 0) { ++ close $CI or die "broken pipe: $!"; ++ } ++ } ++ if ( $rout ) { ++ my $tmp_out = ""; ++ my $bytes_read = sysread($CO, $tmp_out, 4096); ++ $out .= $tmp_out; ++ last if ($bytes_read == 0); ++ } ++ } ++ close $CO or die "broken pipe: $!"; ++ waitpid $pid, 0; ++ ++ return $out; ++} ++ ++# Parser of CAVS test vector file ++# $1: Test vector file ++# $2: Output file for test results ++# return: nothing ++sub parse($$) { ++ my $infile = shift; ++ my $outfile = shift; ++ ++ my $out = ""; ++ ++ my $K = ""; ++ my $H = ""; ++ my $session_id = ""; ++ my $ivlen = 0; ++ my $eklen = ""; ++ my $iklen = ""; ++ ++ open(IN, "<$infile"); ++ while() { ++ ++ my $line = $_; ++ chomp($line); ++ $line =~ s/\r//; ++ ++ if ($line =~ /\[SHA-1\]/) { ++ $iklen = 20; ++ } elsif ($line =~ /\[SHA-256\]/) { ++ $iklen = 32; ++ } elsif ($line =~ /\[SHA-384\]/) { ++ $iklen = 48; ++ } elsif ($line =~ /\[SHA-512\]/) { ++ $iklen = 64; ++ } elsif ($line =~ /^\[IV length\s*=\s*(.*)\]/) { ++ $ivlen = $1; ++ $ivlen = $ivlen / 8; ++ } elsif ($line =~ /^\[encryption key length\s*=\s*(.*)\]/) { ++ $eklen = $1; ++ $eklen = $eklen / 8; ++ } elsif ($line =~ /^K\s*=\s*(.*)/) { ++ $K = $1; ++ $K = substr($K, 8); ++ $K = "00" . $K; ++ } elsif ($line =~ /^H\s*=\s*(.*)/) { ++ $H = $1; ++ } elsif ($line =~ /^session_id\s*=\s*(.*)/) { ++ $session_id = $1; ++ } ++ $out .= $line . "\n"; ++ ++ if ($K ne "" && $H ne "" && $session_id ne "" && ++ $ivlen ne "" && $eklen ne "" && $iklen > 0) { ++ $out .= pipe_through_program("", "./ssh-cavs -H $H -K $K -s $session_id -i $ivlen -e $eklen -m $iklen"); ++ ++ $K = ""; ++ $H = ""; ++ $session_id = ""; ++ } ++ } ++ close IN; ++ $out =~ s/\n/\r\n/g; # make it a dos file ++ open(OUT, ">$outfile") or die "Cannot create output file $outfile: $?"; ++ print OUT $out; ++ close OUT; ++} ++ ++############################################################ ++# ++# let us pretend to be C :-) ++sub main() { ++ ++ my $infile=$ARGV[0]; ++ die "Error: Test vector file $infile not found" if (! -f $infile); ++ ++ my $outfile = $infile; ++ # let us add .rsp regardless whether we could strip .req ++ $outfile =~ s/\.req$//; ++ $outfile .= ".rsp"; ++ if (-f $outfile) { ++ die "Output file $outfile could not be removed: $?" ++ unless unlink($outfile); ++ } ++ print STDERR "Performing tests from source file $infile with results stored in destination file $outfile\n"; ++ ++ # Do the job ++ parse($infile, $outfile); ++} ++ ++########################################### ++# Call it ++main(); ++1; diff --git a/openssh.spec b/openssh.spec index f65e8bb..4d726cb 100644 --- a/openssh.spec +++ b/openssh.spec @@ -166,6 +166,8 @@ Patch711: openssh-6.6p1-log-usepam-no.patch Patch712: openssh-6.3p1-ctr-evp-fast.patch # add cavs test binary for the aes-ctr Patch713: openssh-6.6p1-ctr-cavstest.patch +# add SSH KDF CAVS test driver +Patch714: openssh-6.7p1-kdf-cavs.patch #http://www.sxw.org.uk/computing/patches/openssh.html @@ -413,6 +415,7 @@ popd %patch711 -p1 -b .log-usepam-no %patch712 -p1 -b .evp-ctr %patch713 -p1 -b .ctr-cavs +%patch714 -p1 -b .kdf-cavs # %patch800 -p1 -b .gsskex %patch801 -p1 -b .force_krb @@ -659,6 +662,8 @@ getent passwd sshd >/dev/null || \ %attr(0755,root,root) %dir %{_libexecdir}/openssh %attr(2111,root,ssh_keys) %{_libexecdir}/openssh/ssh-keysign %attr(0755,root,root) %{_libexecdir}/openssh/ctr-cavstest +%attr(0755,root,root) %{_libexecdir}/openssh/ssh-cavs +%attr(0755,root,root) %{_libexecdir}/openssh/ssh-cavs_driver.pl %attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8* %endif