summaryrefslogtreecommitdiff
path: root/usr/src/common/crypto/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/common/crypto/dsa')
-rw-r--r--usr/src/common/crypto/dsa/Makefile35
-rw-r--r--usr/src/common/crypto/dsa/dsa_impl.c600
-rw-r--r--usr/src/common/crypto/dsa/dsa_impl.h136
3 files changed, 771 insertions, 0 deletions
diff --git a/usr/src/common/crypto/dsa/Makefile b/usr/src/common/crypto/dsa/Makefile
new file mode 100644
index 0000000000..3f0a6a0ac8
--- /dev/null
+++ b/usr/src/common/crypto/dsa/Makefile
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# common/crypto/dsa/Makefile
+#
+# include global definitions
+include $(SRC)/Makefile.master
+
+.KEEP_STATE:
+
+FRC:
+
diff --git a/usr/src/common/crypto/dsa/dsa_impl.c b/usr/src/common/crypto/dsa/dsa_impl.c
new file mode 100644
index 0000000000..f2c4c5ccec
--- /dev/null
+++ b/usr/src/common/crypto/dsa/dsa_impl.c
@@ -0,0 +1,600 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * This file contains DSA helper routines common to
+ * the PKCS11 soft token code and the kernel DSA code.
+ */
+
+#include <sys/types.h>
+#include <bignum.h>
+
+#ifdef _KERNEL
+#include <sys/param.h>
+#else
+#include <strings.h>
+#include <cryptoutil.h>
+#endif
+
+#include <sys/crypto/common.h>
+#include "dsa_impl.h"
+
+
+static CK_RV
+convert_rv(BIG_ERR_CODE err)
+{
+ switch (err) {
+
+ case BIG_OK:
+ return (CKR_OK);
+
+ case BIG_NO_MEM:
+ return (CKR_HOST_MEMORY);
+
+ case BIG_NO_RANDOM:
+ return (CKR_DEVICE_ERROR);
+
+ case BIG_INVALID_ARGS:
+ return (CKR_ARGUMENTS_BAD);
+
+ case BIG_DIV_BY_0:
+ default:
+ return (CKR_GENERAL_ERROR);
+ }
+}
+
+/* size is in bits */
+static BIG_ERR_CODE
+DSA_key_init(DSAkey *key, int size)
+{
+ BIG_ERR_CODE err = BIG_OK;
+ int len, len160;
+
+ len = BITLEN2BIGNUMLEN(size);
+ len160 = BIG_CHUNKS_FOR_160BITS;
+ key->size = size;
+ if ((err = big_init(&(key->q), len160)) != BIG_OK)
+ return (err);
+ if ((err = big_init(&(key->p), len)) != BIG_OK)
+ goto ret1;
+ if ((err = big_init(&(key->g), len)) != BIG_OK)
+ goto ret2;
+ if ((err = big_init(&(key->x), len160)) != BIG_OK)
+ goto ret3;
+ if ((err = big_init(&(key->y), len)) != BIG_OK)
+ goto ret4;
+ if ((err = big_init(&(key->k), len160)) != BIG_OK)
+ goto ret5;
+ if ((err = big_init(&(key->r), len160)) != BIG_OK)
+ goto ret6;
+ if ((err = big_init(&(key->s), len160)) != BIG_OK)
+ goto ret7;
+ if ((err = big_init(&(key->v), len160)) != BIG_OK)
+ goto ret8;
+
+ return (BIG_OK);
+
+ret8:
+ big_finish(&(key->s));
+ret7:
+ big_finish(&(key->r));
+ret6:
+ big_finish(&(key->k));
+ret5:
+ big_finish(&(key->y));
+ret4:
+ big_finish(&(key->x));
+ret3:
+ big_finish(&(key->g));
+ret2:
+ big_finish(&(key->p));
+ret1:
+ big_finish(&(key->q));
+ return (err);
+}
+
+static void
+DSA_key_finish(DSAkey *key)
+{
+
+ big_finish(&(key->v));
+ big_finish(&(key->s));
+ big_finish(&(key->r));
+ big_finish(&(key->k));
+ big_finish(&(key->y));
+ big_finish(&(key->x));
+ big_finish(&(key->g));
+ big_finish(&(key->p));
+ big_finish(&(key->q));
+
+}
+
+/*
+ * Generate DSA private x and public y from prime p, subprime q, and base g.
+ */
+static CK_RV
+generate_dsa_key(DSAkey *key, int (*rfunc)(void *, size_t))
+{
+ BIG_ERR_CODE err;
+ int (*rf)(void *, size_t);
+
+ rf = rfunc;
+ if (rf == NULL) {
+#ifdef _KERNEL
+ rf = random_get_pseudo_bytes;
+#else
+ rf = pkcs11_get_urandom;
+#endif
+ }
+ do {
+ if ((err = big_random(&(key->x), DSA_SUBPRIME_BITS, rf)) !=
+ BIG_OK) {
+ return (convert_rv(err));
+ }
+ } while (big_cmp_abs(&(key->x), &(key->q)) > 0);
+
+ if ((err = big_modexp(&(key->y), &(key->g), (&key->x), (&key->p),
+ NULL)) != BIG_OK)
+ return (convert_rv(err));
+
+ return (CKR_OK);
+}
+
+CK_RV
+dsa_genkey_pair(DSAbytekey *bkey)
+{
+ CK_RV rv = CKR_OK;
+ BIG_ERR_CODE brv;
+ DSAkey dsakey;
+ uint32_t prime_bytes;
+ uint32_t subprime_bytes;
+
+ prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
+
+ if ((prime_bytes < MIN_DSA_KEY_LEN) ||
+ (prime_bytes > MAX_DSA_KEY_LEN)) {
+ return (CKR_ATTRIBUTE_VALUE_INVALID);
+ }
+
+ /*
+ * There is no check here that prime_bits must be a multiple of 64,
+ * and thus that prime_bytes must be a multiple of 8.
+ */
+
+ subprime_bytes = CRYPTO_BITS2BYTES(bkey->subprime_bits);
+
+ if (subprime_bytes != DSA_SUBPRIME_BYTES) {
+ return (CKR_ATTRIBUTE_VALUE_INVALID);
+ }
+
+ if (bkey->public_y == NULL || bkey->private_x == NULL) {
+ return (CKR_ARGUMENTS_BAD);
+ }
+
+ /*
+ * Initialize the DSA key.
+ * Note: big_extend takes length in words.
+ */
+ if ((brv = DSA_key_init(&dsakey, bkey->prime_bits)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto cleanexit;
+ }
+
+ /* Convert prime p to bignum. */
+ if ((brv = big_extend(&(dsakey.p),
+ CHARLEN2BIGNUMLEN(prime_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto cleanexit;
+ }
+ bytestring2bignum(&(dsakey.p), bkey->prime, prime_bytes);
+
+ /* Convert prime q to bignum. */
+ if ((brv = big_extend(&(dsakey.q),
+ CHARLEN2BIGNUMLEN(subprime_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto cleanexit;
+ }
+ bytestring2bignum(&(dsakey.q), bkey->subprime, subprime_bytes);
+
+ /* Convert base g to bignum. */
+ if ((brv = big_extend(&(dsakey.g),
+ CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto cleanexit;
+ }
+ bytestring2bignum(&(dsakey.g), bkey->base, bkey->base_bytes);
+
+ /*
+ * Generate DSA key pair.
+ * Note: bignum.len is length of value in words.
+ */
+ if ((rv = generate_dsa_key(&dsakey, bkey->rfunc)) !=
+ CKR_OK) {
+ goto cleanexit;
+ }
+
+ bkey->public_y_bits = CRYPTO_BYTES2BITS(prime_bytes);
+ bignum2bytestring(bkey->public_y, &(dsakey.y), prime_bytes);
+
+ bkey->private_x_bits = CRYPTO_BYTES2BITS(DSA_SUBPRIME_BYTES);
+ bignum2bytestring(bkey->private_x, &(dsakey.x), DSA_SUBPRIME_BYTES);
+
+cleanexit:
+ DSA_key_finish(&dsakey);
+
+ return (rv);
+}
+
+/*
+ * DSA sign operation
+ */
+CK_RV
+dsa_sign(DSAbytekey *bkey, uchar_t *in, uint32_t inlen, uchar_t *out)
+{
+ CK_RV rv = CKR_OK;
+ BIG_ERR_CODE brv;
+ DSAkey dsakey;
+ BIGNUM msg, tmp, tmp1;
+ uint32_t prime_bytes;
+ uint32_t subprime_bytes;
+ uint32_t value_bytes;
+ int (*rf)(void *, size_t);
+
+ prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
+ subprime_bytes = CRYPTO_BITS2BYTES(bkey->subprime_bits);
+
+ if (DSA_SUBPRIME_BYTES != subprime_bytes) {
+ return (CKR_KEY_SIZE_RANGE);
+ }
+
+ value_bytes = CRYPTO_BITS2BYTES(bkey->private_x_bits); /* len of x */
+
+ if (DSA_SUBPRIME_BYTES < value_bytes) {
+ return (CKR_KEY_SIZE_RANGE);
+ }
+
+ /*
+ * Initialize the DH key.
+ * Note: big_extend takes length in words.
+ */
+ if ((brv = DSA_key_init(&dsakey, bkey->prime_bits)) != BIG_OK) {
+ return (CKR_HOST_MEMORY);
+ }
+
+ if ((brv = big_extend(&(dsakey.p),
+ CHARLEN2BIGNUMLEN(prime_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.p), bkey->prime, prime_bytes);
+
+ if ((brv = big_extend(&(dsakey.q),
+ CHARLEN2BIGNUMLEN(subprime_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.q), bkey->subprime, subprime_bytes);
+
+ if ((brv = big_extend(&(dsakey.g),
+ CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.g), bkey->base, bkey->base_bytes);
+
+ if ((brv = big_extend(&(dsakey.x),
+ CHARLEN2BIGNUMLEN(value_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.x), bkey->private_x, value_bytes);
+
+ if ((brv = big_init(&msg, BIG_CHUNKS_FOR_160BITS)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&msg, in, inlen);
+
+ /*
+ * Compute signature.
+ */
+ if ((brv = big_init(&tmp, CHARLEN2BIGNUMLEN(prime_bytes) +
+ 2 * BIG_CHUNKS_FOR_160BITS + 1)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean2;
+ }
+ if ((brv = big_init(&tmp1, 2 * BIG_CHUNKS_FOR_160BITS + 1)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean3;
+ }
+
+ rf = bkey->rfunc;
+ if (rf == NULL) {
+#ifdef _KERNEL
+ rf = random_get_pseudo_bytes;
+#else
+ rf = pkcs11_get_urandom;
+#endif
+ }
+ if ((brv = big_random(&(dsakey.k), DSA_SUBPRIME_BITS, rf)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if ((brv = big_div_pos(NULL, &(dsakey.k), &(dsakey.k),
+ &(dsakey.q))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if ((brv = big_modexp(&tmp, &(dsakey.g), &(dsakey.k), &(dsakey.p),
+ NULL)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if ((brv = big_div_pos(NULL, &(dsakey.r), &tmp, &(dsakey.q))) !=
+ BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+
+ if ((brv = big_ext_gcd_pos(NULL, NULL, &tmp, &(dsakey.q),
+ &(dsakey.k))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if (tmp.sign == -1)
+ if ((brv = big_add(&tmp, &tmp, &(dsakey.q))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4; /* tmp <- k^-1 */
+ }
+
+ if ((brv = big_mul(&tmp1, &(dsakey.x), &(dsakey.r))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if ((brv = big_add(&tmp1, &tmp1, &msg)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if ((brv = big_mul(&tmp, &tmp1, &tmp)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ if ((brv = big_div_pos(NULL, &(dsakey.s), &tmp, &(dsakey.q))) !=
+ BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean4;
+ }
+
+ /*
+ * Signature is in DSA key r and s values, copy to out
+ */
+ bignum2bytestring(out, &(dsakey.r), DSA_SUBPRIME_BYTES);
+ bignum2bytestring(out + DSA_SUBPRIME_BYTES, &(dsakey.s),
+ DSA_SUBPRIME_BYTES);
+
+clean4:
+ big_finish(&tmp1);
+clean3:
+ big_finish(&tmp);
+clean2:
+ big_finish(&msg);
+clean1:
+ DSA_key_finish(&dsakey);
+
+ return (rv);
+}
+
+/*
+ * DSA verify operation
+ */
+CK_RV
+dsa_verify(DSAbytekey *bkey, uchar_t *data, uchar_t *sig)
+{
+ CK_RV rv = CKR_OK;
+ BIG_ERR_CODE brv;
+ DSAkey dsakey;
+ BIGNUM msg, tmp1, tmp2, tmp3;
+ uint32_t prime_bytes;
+ uint32_t subprime_bytes;
+ uint32_t value_bytes;
+
+ prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
+ subprime_bytes = CRYPTO_BITS2BYTES(bkey->subprime_bits);
+
+ if (DSA_SUBPRIME_BYTES != subprime_bytes) {
+ return (CKR_KEY_SIZE_RANGE);
+ }
+
+ if (prime_bytes < bkey->base_bytes) {
+ return (CKR_KEY_SIZE_RANGE);
+ }
+
+ value_bytes = CRYPTO_BITS2BYTES(bkey->public_y_bits); /* len of y */
+ if (prime_bytes < value_bytes) {
+ return (CKR_KEY_SIZE_RANGE);
+ }
+
+ /*
+ * Initialize the DSA key.
+ * Note: big_extend takes length in words.
+ */
+ if (DSA_key_init(&dsakey, bkey->prime_bits) != BIG_OK) {
+ return (CKR_HOST_MEMORY);
+ }
+
+ if ((brv = big_extend(&(dsakey.p),
+ CHARLEN2BIGNUMLEN(prime_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.p), bkey->prime, prime_bytes);
+
+ if ((brv = big_extend(&(dsakey.q),
+ CHARLEN2BIGNUMLEN(subprime_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.q), bkey->subprime, subprime_bytes);
+
+ if ((brv = big_extend(&(dsakey.g),
+ CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.g), bkey->base, bkey->base_bytes);
+
+ if ((brv = big_extend(&(dsakey.y),
+ CHARLEN2BIGNUMLEN(value_bytes))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.y), bkey->public_y, value_bytes);
+
+ /*
+ * Copy signature to DSA key r and s values
+ */
+ if ((brv = big_extend(&(dsakey.r),
+ CHARLEN2BIGNUMLEN(DSA_SUBPRIME_BYTES))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.r), sig, DSA_SUBPRIME_BYTES);
+
+ if ((brv = big_extend(&(dsakey.s),
+ CHARLEN2BIGNUMLEN(DSA_SUBPRIME_BYTES))) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean1;
+ }
+ bytestring2bignum(&(dsakey.s), sig + DSA_SUBPRIME_BYTES,
+ DSA_SUBPRIME_BYTES);
+
+
+ if (big_init(&msg, BIG_CHUNKS_FOR_160BITS) != BIG_OK) {
+ rv = CKR_HOST_MEMORY;
+ goto clean1;
+ }
+ bytestring2bignum(&msg, data, DSA_SUBPRIME_BYTES);
+
+ if (big_init(&tmp1, 2 * CHARLEN2BIGNUMLEN(prime_bytes)) != BIG_OK) {
+ rv = CKR_HOST_MEMORY;
+ goto clean2;
+ }
+ if (big_init(&tmp2, CHARLEN2BIGNUMLEN(prime_bytes)) != BIG_OK) {
+ rv = CKR_HOST_MEMORY;
+ goto clean3;
+ }
+ if (big_init(&tmp3, 2 * BIG_CHUNKS_FOR_160BITS) != BIG_OK) {
+ rv = CKR_HOST_MEMORY;
+ goto clean4;
+ }
+
+ /*
+ * Verify signature against msg.
+ */
+ if (big_ext_gcd_pos(NULL, &tmp2, NULL, &(dsakey.s), &(dsakey.q)) !=
+ BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (tmp2.sign == -1)
+ if (big_add(&tmp2, &tmp2, &(dsakey.q)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5; /* tmp2 <- w */
+ }
+
+ if (big_mul(&tmp1, &msg, &tmp2) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_div_pos(NULL, &tmp1, &tmp1, &(dsakey.q)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5; /* tmp1 <- u_1 */
+ }
+
+ if (big_mul(&tmp2, &tmp2, &(dsakey.r)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_div_pos(NULL, &tmp2, &tmp2, &(dsakey.q)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5; /* tmp2 <- u_2 */
+ }
+
+ if (big_modexp(&tmp1, &(dsakey.g), &tmp1, &(dsakey.p), NULL) !=
+ BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_modexp(&tmp2, &(dsakey.y), &tmp2, &(dsakey.p), NULL) !=
+ BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_mul(&tmp1, &tmp1, &tmp2) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_div_pos(NULL, &tmp1, &tmp1, &(dsakey.p)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_div_pos(NULL, &tmp1, &tmp1, &(dsakey.q)) != BIG_OK) {
+ rv = convert_rv(brv);
+ goto clean5;
+ }
+
+ if (big_cmp_abs(&tmp1, &(dsakey.r)) == 0)
+ rv = CKR_OK;
+ else
+ rv = CKR_SIGNATURE_INVALID;
+
+clean5:
+ big_finish(&tmp3);
+clean4:
+ big_finish(&tmp2);
+clean3:
+ big_finish(&tmp1);
+clean2:
+ big_finish(&msg);
+clean1:
+ DSA_key_finish(&dsakey);
+
+ return (rv);
+}
diff --git a/usr/src/common/crypto/dsa/dsa_impl.h b/usr/src/common/crypto/dsa/dsa_impl.h
new file mode 100644
index 0000000000..c550aaf517
--- /dev/null
+++ b/usr/src/common/crypto/dsa/dsa_impl.h
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _DSA_IMPL_H
+#define _DSA_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <bignum.h>
+
+/* DSA Signature is always 40 bytes */
+#define DSA_SIGNATURE_LENGTH 40
+#define MIN_DSA_KEY_LEN (512 >> 3)
+#define MAX_DSA_KEY_LEN (1024 >> 3)
+
+#define DSA_SUBPRIME_BITS 160
+#define DSA_SUBPRIME_BYTES (DSA_SUBPRIME_BITS >> 3)
+
+#ifdef _KERNEL
+
+#include <sys/sunddi.h>
+#include <sys/crypto/common.h>
+
+#define CK_RV int
+
+#define CKR_OK CRYPTO_SUCCESS
+#define CKR_ARGUMENTS_BAD CRYPTO_ARGUMENTS_BAD
+#define CKR_ATTRIBUTE_VALUE_INVALID CRYPTO_ATTRIBUTE_VALUE_INVALID
+#define CKR_DEVICE_ERROR CRYPTO_DEVICE_ERROR
+#define CKR_GENERAL_ERROR CRYPTO_GENERAL_ERROR
+#define CKR_HOST_MEMORY CRYPTO_HOST_MEMORY
+#define CKR_KEY_SIZE_RANGE CRYPTO_KEY_SIZE_RANGE
+#define CKR_SIGNATURE_INVALID CRYPTO_SIGNATURE_INVALID
+
+int random_get_bytes(uint8_t *ran_out, size_t ran_len);
+int random_get_pseudo_bytes(uint8_t *ran_out, size_t ran_len);
+
+#else
+
+#include <security/cryptoki.h>
+#include <security/pkcs11t.h>
+
+#endif /* _KERNEL */
+
+
+/* DSA key using BIGNUM representations */
+typedef struct {
+ int size; /* key size in bits */
+ BIGNUM p; /* p (<size-bit> prime) */
+ BIGNUM q; /* q (160-bit prime) */
+ BIGNUM g; /* g (the base) */
+ BIGNUM x; /* private key (< q) */
+ BIGNUM y; /* = g^x mod p */
+ BIGNUM k; /* k (random number < q) */
+ BIGNUM r; /* r (signature 1st part) */
+ BIGNUM s; /* s (signature 2st part) */
+ BIGNUM v; /* v (verification value - should be = r) */
+ BIGNUM p_rr; /* 2^(2*(32*p->len)) mod p */
+ BIGNUM q_rr; /* 2^(2*(32*q->len)) mod q */
+} DSAkey;
+
+/* DSA key using byte string representations, useful for parameter lists */
+typedef struct {
+ uint32_t prime_bits; /* size */
+ uchar_t *prime; /* p */
+ uint32_t subprime_bits; /* = 160 */
+ uchar_t *subprime; /* q */
+ uint32_t base_bytes;
+ uchar_t *base; /* g */
+ uchar_t *private_x; /* x */
+ uint32_t private_x_bits;
+ uchar_t *public_y; /* y */
+ uint32_t public_y_bits;
+ uchar_t *signature; /* concat(r, s) */
+ int (*rfunc)(void *, size_t); /* random function */
+} DSAbytekey;
+
+
+CK_RV dsa_genkey_pair(DSAbytekey *bkey);
+
+CK_RV dsa_sign(DSAbytekey *bkey, uchar_t *msg, uint32_t msglen, uchar_t *sig);
+
+CK_RV dsa_verify(DSAbytekey *bkey, uchar_t *msg, uchar_t *sig);
+
+
+/*
+ * The following definitions and declarations are only used by DSA FIPS POST
+ */
+#ifdef _DSA_FIPS_POST
+
+/* DSA FIPS Declarations */
+#define FIPS_DSA_PRIME_LENGTH 128 /* 1024-bits */
+#define FIPS_DSA_SUBPRIME_LENGTH 20 /* 160-bits */
+#define FIPS_DSA_BASE_LENGTH 128 /* 1024-bits */
+#define FIPS_DSA_SEED_LENGTH 20 /* 160-bits */
+#define FIPS_DSA_DIGEST_LENGTH 20 /* 160-bits */
+#define FIPS_DSA_SIGNATURE_LENGTH 40 /* 320-bits */
+
+/* DSA FIPS functions */
+extern int fips_dsa_post(void);
+extern int fips_dsa_genkey_pair(DSAbytekey *);
+extern int fips_dsa_digest_sign(DSAbytekey *, uint8_t *, uint32_t, uint8_t *);
+extern int fips_dsa_verify(DSAbytekey *, uint8_t *, uint8_t *);
+
+#endif /* _DSA_FIPS_POST */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DSA_IMPL_H */