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 ca5222ea819cc5ed797860070b4c6c1aeeb28420 and
7934c9ce2a029c43e3642a492d3b9e494d1542be (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.
diff --git a/docs/HACKING.CRYPTO b/docs/HACKING.CRYPTO
index 21c99c3..381b2a9 100644
--- a/docs/HACKING.CRYPTO
+++ b/docs/HACKING.CRYPTO
@@ -88,7 +88,7 @@
#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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.
diff --git a/os400/initscript.sh b/os400/initscript.sh
index 1d47a1d..a18e24c 100644
--- a/os400/initscript.sh
+++ b/os400/initscript.sh
@@ -49,7 +49,7 @@
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 @@
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}'"
diff --git a/src/kex.c b/src/kex.c
index 95e4d91..c0f9260 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
}
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);
diff --git a/src/libgcrypt.h b/src/libgcrypt.h
index 11d6ad2..2a3f8d1 100644
--- a/src/libgcrypt.h
+++ b/src/libgcrypt.h
@@ -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 *
+
diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
index b4296a2..0dab735 100644
--- a/src/libssh2_priv.h
+++ b/src/libssh2_priv.h
@@ -248,7 +248,7 @@
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;
diff --git a/src/openssl.h b/src/openssl.h
index 3ca71fa..fba0454 100644
--- a/src/openssl.h
+++ b/src/openssl.h
@@ -287,6 +287,8 @@
#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);
diff --git a/src/os400qc3.c b/src/os400qc3.c
index f8e46ab..74fe64b 100644
--- a/src/os400qc3.c
+++ b/src/os400qc3.c
@@ -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 @@
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 @@
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 @@
#include <qc3sigvr.h>
#include <qc3sigcl.h>
#include <qc3pbext.h>
+#include <qc3dh.h>
static Qc3_Format_KEYD0100_T nulltoken = {""};
@@ -883,220 +887,6 @@
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;
-}
-
/*******************************************************************
*
@@ -1445,6 +1235,101 @@
/*******************************************************************
*
+ * 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.
*
*******************************************************************/
diff --git a/src/os400qc3.h b/src/os400qc3.h
index dbaa581..2e2f56a 100644
--- a/src/os400qc3.h
+++ b/src/os400qc3.h
@@ -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 @@
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 @@
#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 @@
_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_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 @@
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
diff --git a/src/wincng.h b/src/wincng.h
index 5219db7..1e9c3ba 100755
--- a/src/wincng.h
+++ b/src/wincng.h
@@ -374,6 +374,8 @@
#define _libssh2_bn_free(bn) \
_libssh2_wincng_bignum_free(bn)
+#define _libssh2_dh_ctx _libssh2_bn *
+
/*******************************************************************/
/*
* Windows CNG backend: forward declarations