Class: OpenSSL::PKey::DSA

Inherits:
PKey
  • Object
show all
Defined in:
ext/rubysl/openssl/ossl_pkey_dsa.c,
ext/rubysl/openssl/ossl_pkey_dsa.c

Overview

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.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from PKey

#sign, #verify

Constructor Details

#newObject #new(size) ⇒ Object #new(string[, pass]) ⇒ Object

Creates a new DSA instance by reading an existing key from string.

Parameters

  • 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.

Examples

DSA.new -> dsa DSA.new(1024) -> dsa DSA.new(File.read(‘dsa.pem’)) -> dsa DSA.new(File.read(‘dsa.pem’), ‘mypassword’) -> dsa



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 212

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;
}

Class Method Details

.generate(size) ⇒ Object

Creates a new DSA instance by generating a private/public key pair from scratch.

Parameters

  • size is an integer representing the desired key size.



178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 178

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;
}

Instance Method Details

#export([cipher, password]) ⇒ aString #to_pem([cipher, password]) ⇒ aString #to_s([cipher, password]) ⇒ aString Also known as: to_pem, to_s

Encodes this DSA to its PEM encoding.

Parameters

  • cipher is an OpenSSL::Cipher.

  • password is a string containing your password.

Examples

DSA.to_pem -> aString DSA.to_pem(cipher, ‘mypassword’) -> aString

Overloads:

  • #export([cipher, password]) ⇒ aString

    Returns:

    • (aString)
  • #to_pem([cipher, password]) ⇒ aString

    Returns:

    • (aString)
  • #to_s([cipher, password]) ⇒ aString

    Returns:

    • (aString)


340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 340

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;
}

#paramsHash

Stores all parameters of key to the hash INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! Don’t use :-)) (I’s up to you)

Returns:

  • (Hash)


415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 415

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;
}

#private?Boolean

Indicates whether this DSA instance has a private key associated with it or not. The private key may be retrieved with DSA#private_key.

Returns:

  • (Boolean)


313
314
315
316
317
318
319
320
321
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 313

static VALUE
ossl_dsa_is_private(VALUE self)
{
    DSA *dsa;

    GetDSA(self, dsa);

    return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse;
}

#public?Boolean

Indicates whether this DSA instance has a public key associated with it or not. The public key may be retrieved with DSA#public_key.

Returns:

  • (Boolean)


294
295
296
297
298
299
300
301
302
303
304
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 294

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;
}

#public_keyObject

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.

Example

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



481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 481

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;
}

#set_key(pub_key, priv_key) ⇒ self

Sets pub_key and priv_key for the DSA instance. priv_key may be nil.

Returns:

  • (self)

#set_pqg(p, q, g) ⇒ self

Sets p, q, g for the DSA instance.

Returns:

  • (self)

#syssign(string) ⇒ aString

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.

Parameters

  • string is a message digest of the original input data to be signed

Example

dsa = OpenSSL::PKey::DSA.new(2048) doc = “Sign me” digest = OpenSSL::Digest::SHA1.digest(doc) sig = dsa.syssign(digest)

Returns:

  • (aString)


521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 521

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;
}

#sysverify(digest, sig) ⇒ Object

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.

Parameters

  • digest is a message digest of the original input data to be signed

  • sig is a DSA signature value

Example

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



566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 566

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;
}

#to_deraString

Encodes this DSA to its DER encoding.

Returns:

  • (aString)


381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 381

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;
}

#to_textaString

Prints all parameters of key to buffer INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! Don’t use :-)) (I’s up to you)

Returns:

  • (aString)


444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'ext/rubysl/openssl/ossl_pkey_dsa.c', line 444

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;
}