int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig,
unsigned int parent, int emptyauth, gnutls_datum_t *privdata, gnutls_datum_t *pubdata);
+/* GnuTLS 3.6.0+ provides this. We have our own for older GnuTLS. There is
+ * also _gnutls_encode_ber_rs_raw() in some older versions, but there were
+ * zero-padding bugs in that, and some of the... less diligently maintained
+ * distributions (like Ubuntu even in 18.04) don't have the fix yet, two
+ * years later. */
+#if GNUTLS_VERSION_NUMBER < 0x030600
+#define gnutls_encode_rs_value oc_gnutls_encode_rs_value
+int oc_gnutls_encode_rs_value(gnutls_datum_t *sig_value, const gnutls_datum_t *r, const gnutls_datum_t *s);
+#endif
char *get_gnutls_cipher(gnutls_session_t session);
return ret;
}
+#if GNUTLS_VERSION_NUMBER < 0x030600
+static void append_bignum(struct oc_text_buf *sig_der, const gnutls_datum_t *d)
+{
+ unsigned char derlen[2];
+
+ buf_append_bytes(sig_der, "\x02", 1); // INTEGER
+ derlen[0] = d->size;
+ /* If it might be interpreted as negative, prepend a zero */
+ if (d->data[0] >= 0x80) {
+ derlen[0]++;
+ derlen[1] = 0;
+ buf_append_bytes(sig_der, derlen, 2);
+ } else {
+ buf_append_bytes(sig_der, derlen, 1);
+ }
+ buf_append_bytes(sig_der, d->data, d->size);
+}
+
+int oc_gnutls_encode_rs_value(gnutls_datum_t *sig, const gnutls_datum_t *sig_r,
+ const gnutls_datum_t *sig_s)
+{
+ struct oc_text_buf *sig_der = NULL;
+ /*
+ * Create the DER-encoded SEQUENCE containing R and S:
+ *
+ * DSASignatureValue ::= SEQUENCE {
+ * r INTEGER,
+ * s INTEGER
+ * }
+ */
+
+ sig_der = buf_alloc();
+ buf_append_bytes(sig_der, "\x30\x80", 2); // SEQUENCE, indeterminate length
+
+ append_bignum(sig_der, sig_r);
+ append_bignum(sig_der, sig_s);
+
+ /* If the length actually fits in one byte (which it should), do
+ * it that way. Else, leave it indeterminate and add two
+ * end-of-contents octets to mark the end of the SEQUENCE. */
+ if (!buf_error(sig_der) && sig_der->pos <= 0x80)
+ sig_der->data[1] = sig_der->pos - 2;
+ else {
+ buf_append_bytes(sig_der, "\0\0", 2);
+ if (buf_error(sig_der))
+ goto out;
+ }
+
+ sig->data = (void *)sig_der->data;
+ sig->size = sig_der->pos;
+ sig_der->data = NULL;
+ out:
+ return buf_free(sig_der);
+}
+#endif /* GnuTLS < 3.6.0 */
+
#endif /* HAVE_TSS2 */
.hierarchy = TPM2_RH_NULL,
.digest.size = 0 };
TPMT_SIG_SCHEME inScheme = { .scheme = TPM2_ALG_ECDSA };
- struct oc_text_buf *sig_der = NULL;
- unsigned char derlen;
+ gnutls_datum_t sig_r, sig_s;
vpn_progress(vpninfo, PRG_DEBUG,
_("TPM2 EC sign function called for %d bytes.\n"),
goto out;
}
- /*
- * Create the DER-encoded SEQUENCE containing R and S:
- *
- * DSASignatureValue ::= SEQUENCE {
- * r INTEGER,
- * s INTEGER
- * }
- */
- sig_der = buf_alloc();
- buf_append_bytes(sig_der, "\x30\x80", 2); // SEQUENCE, indeterminate length
- buf_append_bytes(sig_der, "\x02", 1); // INTEGER
- derlen = tsig->signature.ecdsa.signatureR.size;
- buf_append_bytes(sig_der, &derlen, 1);
- buf_append_bytes(sig_der, tsig->signature.ecdsa.signatureR.buffer, tsig->signature.ecdsa.signatureR.size);
-
- buf_append_bytes(sig_der, "\x02", 1); // INTEGER
- derlen = tsig->signature.ecdsa.signatureS.size;
- buf_append_bytes(sig_der, &derlen, 1);
- buf_append_bytes(sig_der, tsig->signature.ecdsa.signatureS.buffer, tsig->signature.ecdsa.signatureS.size);
-
- /* If the length actually fits in one byte (which it should), do
- * it that way. Else, leave it indeterminate and add two
- * end-of-contents octets to mark the end of the SEQUENCE. */
- if (!buf_error(sig_der) && sig_der->pos <= 0x80)
- sig_der->data[1] = sig_der->pos - 2;
- else {
- buf_append_bytes(sig_der, "\0\0", 2);
- if (buf_error(sig_der))
- goto out;
- }
-
- sig->data = (void *)sig_der->data;
- sig->size = sig_der->pos;
- sig_der->data = NULL;
+ sig_r.data = tsig->signature.ecdsa.signatureR.buffer;
+ sig_r.size = tsig->signature.ecdsa.signatureR.size;
+ sig_s.data = tsig->signature.ecdsa.signatureS.buffer;
+ sig_s.size = tsig->signature.ecdsa.signatureS.size;
- ret = 0;
+ ret = gnutls_encode_rs_value(sig, &sig_r, &sig_s);
out:
- buf_free(sig_der);
free(tsig);
if (key_handle != ESYS_TR_NONE)