1
1
Fork 0

Make libssh2 work again on os400. (#118)

* os400: minimum supported OS version is now V6R1.
Do not log compiler informational messages.

* Implement crypto backend specific Diffie-Hellman computation.

This feature is now needed on os400 because the QC3 library does not
implement bn_mod_exp() natively. Up to now, this function was emulated using
an RSA encryption, but commits ca5222ea81 and
7934c9ce2a (CVE-2016-0787) broke the emulation
because QC3 only supports RSA exponents up to 512 bits.

Happily, QC3 supports a native API for Diffie-Hellman computation, with
opaque random value: this commit implements the use of this API and, as a
side effect, enables support of this feature for any other crypto backend that
would use it.

A "generic" Diffie-Hellman computation internal API supports crypto backends
not implementing their own: this generic API uses the same functions as before.

* Fix typos in docs/HACKING.CRYPTO.
This commit is contained in:
monnerat 2016-11-12 19:15:49 +01:00 committed by Alexander Lamaison
parent c81b2384ac
commit c8c1b4a050
9 changed files with 235 additions and 253 deletions

View File

@ -88,7 +88,7 @@ SHA_DIGEST_LENGTH
#define to 20, the SHA-1 digest length.
libssh2_sha1_ctx
Type of an SHA1 computation context. Generally a struct.
Type of an SHA-1 computation context. Generally a struct.
int libssh2_sha1_init(libssh2_sha1_ctx *x);
Initializes the SHA-1 computation context at x.
@ -102,7 +102,7 @@ Note: if the ctx parameter is modified by the underlying code,
this procedure must be implemented as a macro to map ctx --> &ctx.
void libssh2_sha1_final(libssh2_sha1_ctx ctx,
unsigned char output[SHA1_DIGEST_LEN]);
unsigned char output[SHA_DIGEST_LEN]);
Get the computed SHA-1 signature from context ctx and store it into the
output buffer.
Release the context.
@ -223,7 +223,7 @@ the keylen-byte key. Is invoked just after libssh2_hmac_ctx_init().
Returns 1 for success and 0 for failure.
4) Bidirectional Key ciphers.
4) Bidirectional key ciphers.
_libssh2_cipher_ctx
Type of a cipher computation context.
@ -332,10 +332,50 @@ TripleDES-CBC algorithm identifier initializer.
#define with constant value of type _libssh2_cipher_type().
5) Big numbers.
5) Diffie-Hellman support.
If the crypto-library supports opaque Diffie-Hellman computations, symbol
`libssh2_dh_key_pair' should be #defined as described below and the rest of
this section applies.
Else, the Diffie-Hellman context MUST be defined as `_libssh2_bn *' and
the computation is emulated via calls to _libssh2_bn_rand() and
_libssh2_bn_mod_exp(): all other symbols in this section are unused in this
case.
5.1) Diffie-Hellman context.
_libssh2_dh_ctx
Type of a Diffie-Hellman computation context.
Must always be defined.
5.2) Diffie-Hellman computation procedures.
void libssh2_dh_init(_libssh2_dh_ctx *dhctx);
Initializes the Diffie-Hellman context at `dhctx'. No effective context
creation needed here.
int libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order,
_libssh2_bn_ctx *bnctx);
Generates a Diffie-Hellman key pair using base `g', prime `p' and the given
`group_order'. Can use the given big number context `bnctx' if needed.
The private key is stored as opaque in the Diffie-Hellman context `*dhctx' and
the public key is returned in `public'.
0 is returned upon success, else -1.
If defined, this procedure MUST be implemented as a #define'd macro.
int libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p, _libssh2_bn_ctx * bnctx)
Computes the Diffie-Hellman secret from the previouly created context `*dhctx',
the public key `f' from the other party and the same prime `p' used at
context creation. The result is stored in `secret'.
0 is returned upon success, else -1.
void libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
Destroys Diffie-Hellman context at `dhctx' and resets its storage.
6) Big numbers.
Positive multi-byte integers support is sufficient.
5.1) Computation contexts.
6.1) Computation contexts.
This has a real meaning if the big numbers computations need some context
storage. If not, use a dummy type and functions (macros).
@ -349,7 +389,7 @@ Returns a new multiple precision computation context.
void _libssh2_bn_ctx_free(_libssh2_bn_ctx ctx);
Releases a multiple precision computation context.
5.2) Computation support.
6.2) Computation support.
_libssh2_bn
Type of multiple precision numbers (aka bignumbers or huge integers) for the
crypto library.
@ -396,15 +436,17 @@ random number can be zero. If top is 0, it is set to 1, and if top is 1, the
two most significant bits of the number will be set to 1, so that the product
of two such random numbers will always have 2*bits length. If bottom is true,
the number will be odd.
This procedure is only needed if no specific Diffie-Hellman support is provided.
void _libssh2_bn_mod_exp(_libssh2_bn *r, _libssh2_bn *a,
_libssh2_bn *p, _libssh2_bn *m,
_libssh2_bn_ctx *ctx);
Computes a to the p-th power modulo m and stores the result into r (r=a^p % m).
May use the given context.
This procedure is only needed if no specific Diffie-Hellman support is provided.
6) Private key algorithms.
7) Private key algorithms.
Format of an RSA public key:
a) "ssh-rsa".
b) RSA exponent, MSB first, with high order bit = 0.
@ -448,7 +490,7 @@ Both buffers have to be allocated using LIBSSH2_ALLOC().
Returns 0 if OK, else -1.
This procedure is already prototyped in crypto.h.
6.1) RSA
7.1) RSA
LIBSSH2_RSA
#define as 1 if the crypto library supports RSA, else 0.
If defined as 0, the rest of this section can be omitted.
@ -542,7 +584,7 @@ void _libssh2_rsa_free(libssh2_rsa_ctx *rsactx);
Releases the RSA computation context at rsactx.
6.2) DSA
7.2) DSA
LIBSSH2_DSA
#define as 1 if the crypto library supports DSA, else 0.
If defined as 0, the rest of this section can be omitted.
@ -592,7 +634,7 @@ This procedure is already prototyped in crypto.h.
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx,
const unsigned char *sig,
const unsigned char *m, unsigned long m_len);
Verify (sig, siglen) signature of (m, m_len) using an SHA1 hash and the
Verify (sig, siglen) signature of (m, m_len) using an SHA-1 hash and the
DSA context.
Returns 0 if OK, else -1.
This procedure is already prototyped in crypto.h.
@ -608,7 +650,7 @@ void _libssh2_dsa_free(libssh2_dsa_ctx *dsactx);
Releases the DSA computation context at dsactx.
7) Miscellaneous
8) Miscellaneous
void libssh2_prepare_iovec(struct iovec *vector, unsigned int len);
Prepare len consecutive iovec slots before using them.

View File

@ -49,7 +49,7 @@ setenv TGTCCSID '500' # Target CCSID of objects.
setenv DEBUG '*ALL' # Debug level.
setenv OPTIMIZE '10' # Optimisation level
setenv OUTPUT '*NONE' # Compilation output option.
setenv TGTRLS 'V5R3M0' # Target OS release.
setenv TGTRLS 'V6R1M0' # Target OS release.
setenv IFSDIR '/libssh2' # Installation IFS directory.
# Define ZLIB availability and locations.
@ -180,7 +180,7 @@ make_module()
CMD="CRTCMOD MODULE(${TARGETLIB}/${1}) SRCSTMF('__tmpsrcf.c')"
# CMD="${CMD} SYSIFCOPT(*IFS64IO) OPTION(*INCDIRFIRST *SHOWINC *SHOWSYS)"
CMD="${CMD} SYSIFCOPT(*IFS64IO) OPTION(*INCDIRFIRST)"
CMD="${CMD} LOCALETYPE(*LOCALE)"
CMD="${CMD} LOCALETYPE(*LOCALE) FLAG(10)"
CMD="${CMD} INCDIR('${TOPDIR}/os400/include'"
CMD="${CMD} '/QIBM/ProdData/qadrt/include' '${TOPDIR}/include'"
CMD="${CMD} '${TOPDIR}/os400' '${SRCDIR}'"

View File

@ -98,6 +98,44 @@
} \
}
/*
* Generic Diffie-Hellman computation support.
*
* DH context should be a _libssh2_bn *.
*/
#ifndef libssh2_dh_key_pair
static void libssh2_dh_init(_libssh2_dh_ctx *dhctx)
{
*dhctx = _libssh2_bn_init(); /* Random from client */
}
static int libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order,
_libssh2_bn_ctx *bnctx)
{
/* Generate x and e */
_libssh2_bn_rand(*dhctx, group_order * 8 - 1, 0, -1);
_libssh2_bn_mod_exp(public, g, *dhctx, p, bnctx);
return 0;
}
static int libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p,
_libssh2_bn_ctx * bnctx)
{
/* Compute the shared secret */
_libssh2_bn_mod_exp(secret, f, *dhctx, p, bnctx);
return 0;
}
static void libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
{
_libssh2_bn_free(*dhctx);
*dhctx = NULL;
}
#endif
/*
* diffie_hellman_sha1
@ -124,7 +162,7 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
exchange_state->s_packet = NULL;
exchange_state->k_value = NULL;
exchange_state->ctx = _libssh2_bn_ctx_new();
exchange_state->x = _libssh2_bn_init(); /* Random from client */
libssh2_dh_init(&exchange_state->x);
exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from server) mod p */
exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
@ -133,9 +171,8 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
/* Generate x and e */
_libssh2_bn_rand(exchange_state->x, group_order * 8 - 1, 0, -1);
_libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
exchange_state->ctx);
libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p,
group_order, exchange_state->ctx);
/* Send KEX init */
/* packet_type(1) + String Length(4) + leading 0(1) */
@ -325,8 +362,8 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
exchange_state->h_sig = exchange_state->s;
/* Compute the shared secret */
_libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
exchange_state->x, p, exchange_state->ctx);
libssh2_dh_secret(&exchange_state->x, exchange_state->k,
exchange_state->f, p, exchange_state->ctx);
exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
if (_libssh2_bn_bits(exchange_state->k) % 8) {
/* don't need leading 00 */
@ -693,8 +730,7 @@ static int diffie_hellman_sha1(LIBSSH2_SESSION *session,
}
clean_exit:
_libssh2_bn_free(exchange_state->x);
exchange_state->x = NULL;
libssh2_dh_dtor(&exchange_state->x);
_libssh2_bn_free(exchange_state->e);
exchange_state->e = NULL;
_libssh2_bn_free(exchange_state->f);
@ -750,7 +786,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
exchange_state->s_packet = NULL;
exchange_state->k_value = NULL;
exchange_state->ctx = _libssh2_bn_ctx_new();
exchange_state->x = _libssh2_bn_init(); /* Random from client */
libssh2_dh_init(&exchange_state->x);
exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
exchange_state->f = _libssh2_bn_init_from_bin(); /* g^(Random from server) mod p */
exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
@ -759,9 +795,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
/* Generate x and e */
_libssh2_bn_rand(exchange_state->x, group_order * 8 - 1, 0, -1);
_libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
exchange_state->ctx);
libssh2_dh_key_pair(&exchange_state->x, exchange_state->e, g, p,
group_order, exchange_state->ctx);
/* Send KEX init */
/* packet_type(1) + String Length(4) + leading 0(1) */
@ -951,8 +986,8 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
exchange_state->h_sig = exchange_state->s;
/* Compute the shared secret */
_libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
exchange_state->x, p, exchange_state->ctx);
libssh2_dh_secret(&exchange_state->x, exchange_state->k,
exchange_state->f, p, exchange_state->ctx);
exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
if (_libssh2_bn_bits(exchange_state->k) % 8) {
/* don't need leading 00 */
@ -1321,8 +1356,7 @@ static int diffie_hellman_sha256(LIBSSH2_SESSION *session,
}
clean_exit:
_libssh2_bn_free(exchange_state->x);
exchange_state->x = NULL;
libssh2_dh_dtor(&exchange_state->x);
_libssh2_bn_free(exchange_state->e);
exchange_state->e = NULL;
_libssh2_bn_free(exchange_state->f);

View File

@ -181,3 +181,5 @@
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
#define _libssh2_dh_ctx _libssh2_bn *

View File

@ -248,7 +248,7 @@ typedef struct kmdhgGPshakex_state_t
size_t s_packet_len;
size_t tmp_len;
_libssh2_bn_ctx *ctx;
_libssh2_bn *x;
_libssh2_dh_ctx x;
_libssh2_bn *e;
_libssh2_bn *f;
_libssh2_bn *k;

View File

@ -287,6 +287,8 @@ int _libssh2_md5_init(libssh2_md5_ctx *ctx);
#define _libssh2_bn_bits(bn) BN_num_bits(bn)
#define _libssh2_bn_free(bn) BN_clear_free(bn)
#define _libssh2_dh_ctx _libssh2_bn *
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Patrick Monnerat, D+H <patrick.monnerat@dh.com>
* Copyright (C) 2015-2016 Patrick Monnerat, D+H <patrick.monnerat@dh.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@ -115,6 +115,9 @@ static int sshdsapubkey(LIBSSH2_SESSION *session, char **sshpubkey,
const char *method);
#endif
static unsigned char OID_dhKeyAgreement[] =
{9, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 1, 3, 1};
/* PKCS#5 support. */
@ -206,7 +209,7 @@ static const pkcs5algo des_EDE3_CBC = {
OID_des_EDE3_CBC, parse_iv, Qc3_TDES, 8, Qc3_CBC, Qc3_Pad_Counter,
'\0', 24, 0, 0, 8, 8, 0
};
/* rc2CBC OID: 1.2.840.113549.3.2 */
static const unsigned char OID_rc2CBC[] = {
8, 40 + 2, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02
@ -330,6 +333,7 @@ static const char fopenrbmode[] = "rb";
#include <qc3sigvr.h>
#include <qc3sigcl.h>
#include <qc3pbext.h>
#include <qc3dh.h>
static Qc3_Format_KEYD0100_T nulltoken = {""};
@ -883,220 +887,6 @@ _libssh2_random(unsigned char *buf, int len)
Qc3PRN_TYPE_NORMAL, Qc3PRN_NO_PARITY, (char *) &ecnull);
}
int
_libssh2_bn_rand(_libssh2_bn *bn, int bits, int top, int bottom)
{
int len;
int i;
if (!bn || bits <= 0)
return -1;
len = (bits + 7) >> 3;
if (_libssh2_bn_resize(bn, len))
return -1;
_libssh2_random(bn->bignum, len);
i = ((bits - 1) & 07) + 1;
bn->bignum[len - 1] &= (1 << i) - 1;
switch (top) {
case 1:
if (bits > 1)
if (i > 1)
bn->bignum[len - 1] |= 1 << (i - 2);
else
bn->bignum[len - 2] |= 0x80;
/* Fall into. */
case 0:
bn->bignum[len - 1] |= 1 << (i - 1);
break;
}
if (bottom)
*bn->bignum |= 0x01;
return 0;
}
static int
_libssh2_bn_lshift(_libssh2_bn *bn)
{
int i;
int c = 0;
if (!bn)
return -1;
if (_libssh2_bn_resize(bn, (_libssh2_bn_bits(bn) + 8) >> 3))
return -1;
for (i = 0; i < bn->length; i++) {
if (bn->bignum[i] & 0x80)
c |= 0x02;
bn->bignum[i] = (bn->bignum[i] << 1) | (c & 0x01);
c >>= 1;
}
return 0;
}
static int
_libssh2_bn_rshift(_libssh2_bn *bn)
{
int i;
int c = 0;
if (!bn)
return -1;
for (i = bn->length; i--;) {
if (bn->bignum[i] & 0x01)
c |= 0x100;
bn->bignum[i] = (bn->bignum[i] >> 1) | (c & 0x80);
c >>= 1;
}
if (_libssh2_bn_resize(bn, (_libssh2_bn_bits(bn) + 7) >> 3))
return -1;
return 0;
}
static void
_libssh2_bn_swap(_libssh2_bn *bn1, _libssh2_bn *bn2)
{
_libssh2_bn t = *bn1;
*bn1 = *bn2;
*bn2 = t;
}
static int
_libssh2_bn_subtract(_libssh2_bn *d, _libssh2_bn *bn1, _libssh2_bn *bn2)
{
int c = 0;
int i;
if (bn1->length < bn2->length)
return -1;
if (_libssh2_bn_resize(d, bn1->length))
return -1;
for (i = 0; i < bn2->length; i++) {
c += (int) bn1->bignum[i] - (int) bn2->bignum[i];
d->bignum[i] = c;
c = c < 0? -1: 0;
}
for (; c && i < bn1->length; i++) {
c += (int) bn1->bignum[i];
d->bignum[i] = c;
c = c < 0? -1: 0;
}
if (_libssh2_bn_resize(d, (_libssh2_bn_bits(d) + 7) >> 3))
return -1;
return c;
}
int
_libssh2_os400qc3_bn_mod_exp(_libssh2_bn *r, _libssh2_bn *a, _libssh2_bn *p,
_libssh2_bn *m)
{
_libssh2_bn *mp;
_libssh2_bn *rp;
asn1Element *rsapubkey;
asn1Element *subjpubkeyinfo;
unsigned char *av;
unsigned char *rv;
char *keydbuf;
Qc3_Format_ALGD0400_T algd;
Qc3_Format_KEYD0200_T *keyd;
Qus_EC_t errcode;
int sc;
int outlen;
int ret = -1;
/* There is no support for this function in the Qc3 crypto-library.
Since a RSA encryption performs this function, we can emulate it
by creating an RSA public key in ASN.1 SubjectPublicKeyInfo format
from p (exponent) and m (modulus) and encrypt a with this key. The
encryption output is the function result.
Problem: the Qc3EncryptData procedure only succeeds if the data bit
count is less than the modulus bit count. To satisfy this condition,
we multiply the modulus by a power of two and adjust the result
accordingly. */
if (!r || !a || !p)
return ret;
mp = _libssh2_bn_init();
if (!mp)
return ret;
if (_libssh2_bn_from_bn(mp, m)) {
_libssh2_bn_free(mp);
return ret;
}
for (sc = 0; _libssh2_bn_bits(mp) <= 8 * a->length; sc++)
if (_libssh2_bn_lshift(mp)) {
_libssh2_bn_free(mp);
return ret;
}
rsapubkey = rsapublickey(p, mp);
subjpubkeyinfo = rsasubjectpublickeyinfo(rsapubkey);
asn1delete(rsapubkey);
if (!rsapubkey || !subjpubkeyinfo) {
asn1delete(rsapubkey);
asn1delete(subjpubkeyinfo);
_libssh2_bn_free(mp);
return ret;
}
av = (unsigned char *) alloca(a->length);
rv = (unsigned char *) alloca(mp->length);
keydbuf = alloca(sizeof *keyd +
subjpubkeyinfo->end - subjpubkeyinfo->header);
if (av && rv && keydbuf) {
_libssh2_bn_to_bin(a, av);
algd.Public_Key_Alg = Qc3_RSA;
algd.PKA_Block_Format = Qc3_Zero_Pad;
memset(algd.Reserved, 0, sizeof algd.Reserved);
algd.Signing_Hash_Alg = 0;
keyd = (Qc3_Format_KEYD0200_T *) keydbuf;
keyd->Key_Type = Qc3_RSA_Public;
keyd->Key_String_Len = subjpubkeyinfo->end - subjpubkeyinfo->header;
keyd->Key_Format = Qc3_BER_String;
memset(keyd->Reserved, 0, sizeof keyd->Reserved);
memcpy(keydbuf + sizeof *keyd, subjpubkeyinfo->header,
keyd->Key_String_Len);
set_EC_length(errcode, sizeof errcode);
Qc3EncryptData(av, (int *) &a->length, Qc3_Data, (char *) &algd,
Qc3_Alg_Public_Key, keydbuf, Qc3_Key_Parms, anycsp,
NULL, rv, (int *) &mp->length, &outlen, &errcode);
if (!errcode.Bytes_Available) {
_libssh2_bn_from_bin(r, outlen, rv);
if (!sc)
ret = 0;
else {
rp = _libssh2_bn_init();
if (rp) {
do {
_libssh2_bn_rshift(mp);
if (!_libssh2_bn_subtract(rp, r, mp))
_libssh2_bn_swap(r, rp);
} while (--sc);
_libssh2_bn_free(rp);
ret = 0;
}
}
}
}
asn1delete(subjpubkeyinfo);
_libssh2_bn_free(mp);
return ret;
}
/*******************************************************************
*
@ -1443,6 +1233,101 @@ _libssh2_rsa_new(libssh2_rsa_ctx **rsa,
}
/*******************************************************************
*
* OS/400 QC3 crypto-library backend: Diffie-Hellman support.
*
*******************************************************************/
void
_libssh2_os400qc3_dh_init(_libssh2_dh_ctx *dhctx)
{
memset((char *) dhctx, 0, sizeof *dhctx);
}
int
_libssh2_os400qc3_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
_libssh2_bn *g, _libssh2_bn *p, int group_order)
{
asn1Element *prime;
asn1Element *base;
asn1Element *dhparameter;
asn1Element *dhkeyagreement;
asn1Element *pkcs3;
int pkcs3len;
char *pubkey;
int pubkeysize;
int pubkeylen;
Qus_EC_t errcode;
(void) group_order;
/* Build the PKCS#3 structure. */
base = asn1uint(g);
prime = asn1uint(p);
dhparameter = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED,
prime, base, NULL);
asn1delete(base);
asn1delete(prime);
dhkeyagreement = asn1bytes(ASN1_OBJ_ID,
OID_dhKeyAgreement + 1, OID_dhKeyAgreement[0]);
pkcs3 = asn1container(ASN1_SEQ | ASN1_CONSTRUCTED,
dhkeyagreement, dhparameter, NULL);
asn1delete(dhkeyagreement);
asn1delete(dhparameter);
if (!base || !prime || !dhparameter ||
!dhkeyagreement || !dhparameter || !pkcs3) {
asn1delete(pkcs3);
return -1;
}
pkcs3len = pkcs3->end - pkcs3->header;
pubkeysize = (_libssh2_bn_bits(p) + 7) >> 3;
pubkey = alloca(pubkeysize);
set_EC_length(errcode, sizeof errcode);
Qc3GenDHKeyPair((char *) pkcs3->header, &pkcs3len, anycsp, NULL,
dhctx->token, pubkey, &pubkeysize, &pubkeylen, &errcode);
asn1delete(pkcs3);
if (errcode.Bytes_Available)
return -1;
return _libssh2_bn_from_bin(public, pubkeylen, (unsigned char *) pubkey);
}
int
_libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p)
{
char *pubkey;
int pubkeysize;
char *secretbuf;
int secretbufsize;
int secretbuflen;
Qus_EC_t errcode;
pubkeysize = (_libssh2_bn_bits(f) + 7) >> 3;
pubkey = alloca(pubkeysize);
_libssh2_bn_to_bin(f, pubkey);
secretbufsize = (_libssh2_bn_bits(p) + 7) >> 3;
secretbuf = alloca(pubkeysize);
set_EC_length(errcode, sizeof errcode);
Qc3CalculateDHSecretKey(dhctx->token, pubkey, &pubkeysize,
secretbuf, &secretbufsize, &secretbuflen, &errcode);
if (errcode.Bytes_Available)
return -1;
return _libssh2_bn_from_bin(secret,
secretbuflen, (unsigned char *) secretbuf);
}
void
_libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx)
{
if (!null_token(dhctx->token)) {
Qc3DestroyAlgorithmContext(dhctx->token, (char *) &ecnull);
memset((char *) dhctx, 0, sizeof *dhctx);
}
}
/*******************************************************************
*
* OS/400 QC3 crypto-library backend: PKCS#5 supplement.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Patrick Monnerat, D+H <patrick.monnerat@dh.com>
* Copyright (C) 2015-2016 Patrick Monnerat, D+H <patrick.monnerat@dh.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@ -210,6 +210,10 @@ typedef struct { /* Algorithm description. */
int keylen; /* Key length. */
} _libssh2_os400qc3_cipher_t;
typedef struct { /* Diffie-Hellman context. */
char token[8]; /* Context token. */
} _libssh2_os400qc3_dh_ctx;
/*******************************************************************
*
* OS/400 QC3 crypto-library backend: Define global types/codes.
@ -277,8 +281,6 @@ typedef struct { /* Algorithm description. */
#define _libssh2_bn_ctx_free(bnctx) ((void) 0)
#define _libssh2_bn_init_from_bin() _libssh2_bn_init()
#define _libssh2_bn_mod_exp(r, a, p, m, ctx) \
_libssh2_os400qc3_bn_mod_exp(r, a, p, m)
#define _libssh2_bn_bytes(bn) ((bn)->length)
#define _libssh2_cipher_type(name) _libssh2_os400qc3_cipher_t name
@ -309,6 +311,14 @@ typedef struct { /* Algorithm description. */
_libssh2_os400qc3_rsa_sha1_signv(session, sig, siglen, \
count, vector, ctx)
#define _libssh2_dh_ctx _libssh2_os400qc3_dh_ctx
#define libssh2_dh_init(dhctx) _libssh2_os400qc3_dh_init(dhctx)
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
_libssh2_os400qc3_dh_key_pair(dhctx, public, g, p, group_order)
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
_libssh2_os400qc3_dh_secret(dhctx, secret, f, p)
#define libssh2_dh_dtor(dhctx) _libssh2_os400qc3_dh_dtor(dhctx)
/*******************************************************************
*
@ -324,10 +334,6 @@ extern int _libssh2_bn_from_bin(_libssh2_bn *bn, int len,
extern int _libssh2_bn_set_word(_libssh2_bn *bn, unsigned long val);
extern int _libssh2_bn_to_bin(_libssh2_bn *bn, unsigned char *val);
extern void _libssh2_random(unsigned char *buf, int len);
extern int _libssh2_bn_rand(_libssh2_bn *bn, int bits,
int top, int bottom);
extern int _libssh2_os400qc3_bn_mod_exp(_libssh2_bn *r, _libssh2_bn *a,
_libssh2_bn *p, _libssh2_bn *m);
extern void _libssh2_os400qc3_crypto_dtor(_libssh2_os400qc3_crypto_ctx *x);
extern int libssh2_os400qc3_hash_init(Qc3_Format_ALGD0100_T *x,
unsigned int algo);
@ -352,6 +358,15 @@ extern int _libssh2_os400qc3_rsa_sha1_signv(LIBSSH2_SESSION *session,
int veccount,
const struct iovec vector[],
libssh2_rsa_ctx *ctx);
extern void _libssh2_os400qc3_dh_init(_libssh2_dh_ctx *dhctx);
extern int _libssh2_os400qc3_dh_key_pair(_libssh2_dh_ctx *dhctx,
_libssh2_bn *public,
_libssh2_bn *g,
_libssh2_bn *p, int group_order);
extern int _libssh2_os400qc3_dh_secret(_libssh2_dh_ctx *dhctx,
_libssh2_bn *secret,
_libssh2_bn *f, _libssh2_bn *p);
extern void _libssh2_os400qc3_dh_dtor(_libssh2_dh_ctx *dhctx);
#endif

View File

@ -374,6 +374,8 @@ _libssh2_bn *_libssh2_wincng_bignum_init(void);
#define _libssh2_bn_free(bn) \
_libssh2_wincng_bignum_free(bn)
#define _libssh2_dh_ctx _libssh2_bn *
/*******************************************************************/
/*
* Windows CNG backend: forward declarations