Support for the Ruby 2.4 series has ended. See here for reference.
DSA
, the Digital Signature Algorithm, is specified in NIST's FIPS 186-3. It is an asymmetric public key algorithm that may be used similar to e.g. RSA
. Please note that for OpenSSL
versions prior to 1.0.0 the digest algorithms OpenSSL::Digest::DSS (equivalent to SHA) or OpenSSL::Digest::DSS1 (equivalent to SHA-1) must be used for issuing signatures with a DSA
key using OpenSSL::PKey#sign. Starting with OpenSSL
1.0.0, digest algorithms are no longer restricted, any Digest
may be used for signing.
Creates a new DSA
instance by generating a private/public key pair from scratch.
size
is an integer representing the desired key size.
static VALUE ossl_dsa_s_generate(VALUE klass, VALUE size) { DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */ VALUE obj = dsa_instance(klass, dsa); if (obj == Qfalse) { DSA_free(dsa); ossl_raise(eDSAError, NULL); } return obj; }
Creates a new DSA
instance by reading an existing key from string
.
size
is an integer representing the desired key size.
string
contains a DER or PEM encoded key.
pass
is a string that contains an optional password.
DSA.new -> dsa DSA.new(1024) -> dsa DSA.new(File.read('dsa.pem')) -> dsa DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; DSA *dsa; BIO *in; VALUE arg, pass; GetPKey(self, pkey); if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { dsa = DSA_new(); } else if (RB_INTEGER_TYPE_P(arg)) { if (!(dsa = dsa_generate(NUM2INT(arg)))) { ossl_raise(eDSAError, NULL); } } else { pass = ossl_pem_passwd_value(pass); arg = ossl_to_der_if_possible(arg); in = ossl_obj2bio(arg); dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass); if (!dsa) { OSSL_BIO_reset(in); dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); } if (!dsa) { OSSL_BIO_reset(in); dsa = d2i_DSAPrivateKey_bio(in, NULL); } if (!dsa) { OSSL_BIO_reset(in); dsa = d2i_DSA_PUBKEY_bio(in, NULL); } if (!dsa) { OSSL_BIO_reset(in); #define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \ (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u)) dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); #undef PEM_read_bio_DSAPublicKey } BIO_free(in); if (!dsa) { ossl_clear_error(); ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); } } if (!EVP_PKEY_assign_DSA(pkey, dsa)) { DSA_free(dsa); ossl_raise(eDSAError, NULL); } return self; }
Encodes this DSA
to its PEM encoding.
cipher
is an OpenSSL::Cipher
.
password
is a string containing your password.
DSA.to_pem -> aString DSA.to_pem(cipher, 'mypassword') -> aString
static VALUE ossl_dsa_export(int argc, VALUE *argv, VALUE self) { DSA *dsa; BIO *out; const EVP_CIPHER *ciph = NULL; VALUE cipher, pass, str; GetDSA(self, dsa); rb_scan_args(argc, argv, "02", &cipher, &pass); if (!NIL_P(cipher)) { ciph = GetCipherPtr(cipher); pass = ossl_pem_passwd_value(pass); } if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDSAError, NULL); } if (DSA_HAS_PRIVATE(dsa)) { if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0, ossl_pem_passwd_cb, (void *)pass)){ BIO_free(out); ossl_raise(eDSAError, NULL); } } else { if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) { BIO_free(out); ossl_raise(eDSAError, NULL); } } str = ossl_membio2str(out); return str; }
Stores all parameters of key to the hash INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! Don't use :-)) (I's up to you)
static VALUE ossl_dsa_get_params(VALUE self) { DSA *dsa; VALUE hash; const BIGNUM *p, *q, *g, *pub_key, *priv_key; GetDSA(self, dsa); DSA_get0_pqg(dsa, &p, &q, &g); DSA_get0_key(dsa, &pub_key, &priv_key); hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p)); rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q)); rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g)); rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key)); rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key)); return hash; }
Indicates whether this DSA
instance has a private key associated with it or not. The private key may be retrieved with DSA#private_key.
static VALUE ossl_dsa_is_private(VALUE self) { DSA *dsa; GetDSA(self, dsa); return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse; }
Indicates whether this DSA
instance has a public key associated with it or not. The public key may be retrieved with DSA#public_key
.
static VALUE ossl_dsa_is_public(VALUE self) { DSA *dsa; const BIGNUM *bn; GetDSA(self, dsa); DSA_get0_key(dsa, &bn, NULL); return bn ? Qtrue : Qfalse; }
Returns a new DSA
instance that carries just the public key information. If the current instance has also private key information, this will no longer be present in the new instance. This feature is helpful for publishing the public key information without leaking any of the private information.
dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information pub_key = dsa.public_key # has only the public part available pub_key_der = pub_key.to_der # it's safe to publish this
static VALUE ossl_dsa_to_public_key(VALUE self) { EVP_PKEY *pkey; DSA *dsa; VALUE obj; GetPKeyDSA(self, pkey); /* err check performed by dsa_instance */ #define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \ (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); #undef DSAPublicKey_dup obj = dsa_instance(rb_obj_class(self), dsa); if (obj == Qfalse) { DSA_free(dsa); ossl_raise(eDSAError, NULL); } return obj; }
Sets pub_key
and priv_key
for the DSA
instance. priv_key
may be nil.
Computes and returns the DSA
signature of string
, where string
is expected to be an already-computed message digest of the original input data. The signature is issued using the private key of this DSA
instance.
string
is a message digest of the original input data to be signed
dsa = OpenSSL::PKey::DSA.new(2048) doc = "Sign me" digest = OpenSSL::Digest::SHA1.digest(doc) sig = dsa.syssign(digest)
static VALUE ossl_dsa_sign(VALUE self, VALUE data) { DSA *dsa; const BIGNUM *dsa_q; unsigned int buf_len; VALUE str; GetDSA(self, dsa); DSA_get0_pqg(dsa, NULL, &dsa_q, NULL); if (!dsa_q) ossl_raise(eDSAError, "incomplete DSA"); if (!DSA_PRIVATE(self, dsa)) ossl_raise(eDSAError, "Private DSA key needed!"); StringValue(data); str = rb_str_new(0, DSA_size(dsa)); if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *)RSTRING_PTR(str), &buf_len, dsa)) { /* type is ignored (0) */ ossl_raise(eDSAError, NULL); } rb_str_set_len(str, buf_len); return str; }
Verifies whether the signature is valid given the message digest input. It does so by validating sig
using the public key of this DSA
instance.
digest
is a message digest of the original input data to be signed
sig
is a DSA
signature value
dsa = OpenSSL::PKey::DSA.new(2048) doc = "Sign me" digest = OpenSSL::Digest::SHA1.digest(doc) sig = dsa.syssign(digest) puts dsa.sysverify(digest, sig) # => true
static VALUE ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) { DSA *dsa; int ret; GetDSA(self, dsa); StringValue(digest); StringValue(sig); /* type is ignored (0) */ ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest), (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), dsa); if (ret < 0) { ossl_raise(eDSAError, NULL); } else if (ret == 1) { return Qtrue; } return Qfalse; }
Encodes this DSA
to its DER encoding.
static VALUE ossl_dsa_to_der(VALUE self) { DSA *dsa; int (*i2d_func)(DSA *, unsigned char **); unsigned char *p; long len; VALUE str; GetDSA(self, dsa); if(DSA_HAS_PRIVATE(dsa)) i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey; else i2d_func = i2d_DSA_PUBKEY; if((len = i2d_func(dsa, NULL)) <= 0) ossl_raise(eDSAError, NULL); str = rb_str_new(0, len); p = (unsigned char *)RSTRING_PTR(str); if(i2d_func(dsa, &p) < 0) ossl_raise(eDSAError, NULL); ossl_str_adjust(str, p); return str; }
Prints all parameters of key to buffer INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! Don't use :-)) (I's up to you)
static VALUE ossl_dsa_to_text(VALUE self) { DSA *dsa; BIO *out; VALUE str; GetDSA(self, dsa); if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDSAError, NULL); } if (!DSA_print(out, dsa, 0)) { /* offset = 0 */ BIO_free(out); ossl_raise(eDSAError, NULL); } str = ossl_membio2str(out); return str; }