I wanna use the DSA signature algorithms of OpenSSL to verify RRSIG
and DNSKEY DNSSEC resource records. This is described in RFC2536 (a very
short RFC).
As far as I could try it out (see my attachement) there are two ways
to sign and verify with OpenSSL/DSA: via the EVP interface and via the
DSA interface directly. If I try to sign with one method and verify with
the other that fails. What standards do these methods conform to, what
is the difference between them and what do I need for my purpose? Also I
have found two different ways to create a DSA key yielding apparently
different results (see the sample code). Basically for me it is about
verifying signatures, not about creating such signatures.
<<program output:>>
(pub)key:
3081F13081A906072A8648CE38040130819D024100EECFDC5C3B730FE9D0A3D25C4B8EF27A7F93D7A8A0047065DB55D881A40CC11A620D65C5BD3A720D187300B25A59E051CCB203BBE13731FC7E65B6371D1CFDD9021500B6334A5665A680A9D017C760CFDEF2FD1FECF6A90241008D7623CF35A041F469B32EDA37ECF551485154047E11FE10DA003FEAB1DF88007860C1F0AE32990B29B52EE6DB6BAFDF1A7FF9FD76CFD5B417861ABE3782F4C3034300024019A7A450C6FE998742DF5D3E0F59C2E9D7D90D6861DA6E912AEB66BCA202FFBE981A381414213BB5504B582AC27A1ACFB8B203366A076BCCF179FC471C2E4CB7
asn1 repr of pubkey is the same
signed message: (method #1, DSA interface)
302C02146F4A174CF347EF3FD2796D1858CADBD4A033DA1F02147DA2FB1329E82509C699806D92BB0713272C1651
signed message: 46 Bytes
signature valid
signed message: (method #2, EVP interface)
302C02142F5296C21FA0956049F124A58621084ADF680BB402140BDD997234B82C901999FA096EFB697D864086BD
signed message: 46 Bytes
authentic (verified with the same method)
invalid signature (verified with the other first method)
#include <string.h>
#include <stdio.h>
#include <openssl/dsa.h>
#include <openssl/ssl.h>
#include <assert.h>
#ifndef INCL
typedef unsigned char uchar;
typedef int bool;
#define true 1
#define false 0
enum PrnHexFlags { PRNHEX_NOSEP = 1 };
void prn_as_hex(FILE *out, const char *message, const uchar *digest, int len, int flags ) { int i;
bool prnsep; prnsep=!(flags&PRNHEX_NOSEP);
fprintf(out,message); for( i=0; i<len;i++) fprintf(out,i&&prnsep?":%02X":"%02X",digest[i]); fputc('\n',out);
}
EVP_PKEY* generate_DSA_key(int bits) {
// build parameters first
EVP_PKEY_CTX *ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx_params, bits);
EVP_PKEY_paramgen_init(ctx_params);
EVP_PKEY* pkey_params = NULL;
EVP_PKEY_paramgen(ctx_params, &pkey_params);
// using parameters, build DSA keypair
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey_params, NULL);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY* pkey = NULL;
EVP_PKEY_keygen(ctx, &pkey);
// cleanup everything but the final key
EVP_PKEY_free(pkey_params);
EVP_PKEY_CTX_free(ctx_params);
EVP_PKEY_CTX_free(ctx);
return pkey;
// f.i.:
//DSA* dsa = EVP_PKEY_get1_DSA(pkey);
//BIO* bio = BIO_new_fp(stdout, BIO_NOCLOSE);
//PEM_write_bio_DSAPrivateKey(bio, dsa, NULL, NULL, 0, NULL, NULL);
//BIO_flush(bio);
//DSA_free(dsa);
}
#endif
int main(int argc, char *argv[]) {
const char *msg = "Hello world!"; int msglen, res; size_t sign_msglen_; uchar *signed_msg, *signed_msg_;
EVP_PKEY *privkey, *pubkey; int authstatus; //uchar *pbkraw; size_t pbklen;
EVP_MD_CTX *signctx, *verifyctx; DSA *dsakey; uint sign_msglen;
int len, len_; uchar *keyptr, *asn1key, *asn1key_;
//const BIGNUM *pubkey_bn; uchar *bnbuf; int bnbuflen;
OPENSSL_init(); OpenSSL_add_all_algorithms();
//netwcomm_init();
msglen=strlen(msg);
//privkey = generate_DSA_key(71); // 128 -> 2*223
// assert false:
//res = EVP_PKEY_get_raw_public_key(privkey,NULL,&pbklen); assert(res>0);
//pbkraw = (uchar*)malloc(pbklen);
//res = EVP_PKEY_get_raw_public_key(privkey,pbkraw,&pbklen); assert(res>0);
//EVP_PKEY_print_private(stdout_bio,privkey,0,NULL); // print_public does not do anything else
//EVP_PKEY_assign_RSA(pkey, rsa); PKEY := DSA-key
//dsakey = EVP_PKEY_get0_DSA(privkey);
dsakey = DSA_new();
res = DSA_generate_parameters_ex(dsakey,71,NULL,0,NULL,NULL,NULL); assert(res>0);
res = DSA_generate_key(dsakey); assert(res>0);
privkey = EVP_PKEY_new();
EVP_PKEY_assign_DSA(privkey,dsakey);
len = i2d_DSA_PUBKEY(dsakey,NULL); keyptr = asn1key = alloca(len); len = i2d_DSA_PUBKEY(dsakey,&keyptr);
len_ = i2d_PUBKEY(privkey,NULL); keyptr = asn1key_ = alloca(len_); len_ = i2d_PUBKEY(privkey,&keyptr);
prn_as_hex(stdout,"(pub)key: ", asn1key, len, PRNHEX_NOSEP );
if(len==len_&&!memcmp(asn1key,asn1key_,len)) printf("asn1 repr of pubkey is the same\n");
//i2d_DSAPrivateKey
//DSA_sign_setup();
DSA_sign(0, (uchar*)msg, msglen, NULL, &sign_msglen, dsakey );
signed_msg = (uchar*)malloc(sign_msglen);
DSA_sign(0, (uchar*)msg, msglen, signed_msg, &sign_msglen, dsakey );
prn_as_hex(stdout,"signed message: ", signed_msg, sign_msglen, PRNHEX_NOSEP );
printf("signed message: %i Bytes\n", sign_msglen);
authstatus = DSA_verify(0, (uchar*)msg, msglen, signed_msg, sign_msglen, dsakey );
if(authstatus==1) printf("signature valid\n");
else if(authstatus==0) printf("invalid signature\n");
else printf("error at signature verification\n"); // -1
//pubkey_bn = DSA_get0_pub_key(dsakey);
//bnbuf = alloca(bnbuflen=BN_num_bytes(pubkey_bn));
//BN_bn2bin(pubkey_bn,bnbuf);
//prn_as_hex(stdout," pubkey2bin: ", bnbuf,bnbuflen,PRNHEX_NOSEP);
//printf(" pubkey2bin: %i Bytes\n",bnbuflen);
signctx = EVP_MD_CTX_create();
res = EVP_DigestSignInit( signctx, NULL, EVP_sha1(), NULL, privkey ); assert(res>0);
res = EVP_DigestSignUpdate( signctx, msg, msglen ); assert(res>0);
res = EVP_DigestSignFinal( signctx, NULL, &sign_msglen_ ); assert(res>0);
signed_msg_ = (uchar*)malloc(sign_msglen_);
res = EVP_DigestSignFinal( signctx, signed_msg_, &sign_msglen_ );
EVP_MD_CTX_free(signctx);
prn_as_hex(stdout,"signed message: ", signed_msg_, sign_msglen_, PRNHEX_NOSEP );
printf("signed message: %li Bytes\n", sign_msglen_);
pubkey = privkey;
verifyctx = EVP_MD_CTX_create();
res = EVP_DigestVerifyInit( verifyctx, NULL, EVP_sha1(), NULL, pubkey ); assert(res>0);
res = EVP_DigestVerifyUpdate( verifyctx, msg, msglen ); assert(res>0);
authstatus = EVP_DigestVerifyFinal( verifyctx, signed_msg_, sign_msglen_ );
if (authstatus==1) printf("authentic\n");
else if(authstatus==0) printf("not authentic (0)\n");
else printf("error at signature verification\n");
EVP_MD_CTX_free(verifyctx);
authstatus = DSA_verify(0, (uchar*)msg, msglen, signed_msg_, sign_msglen_, dsakey );
if(authstatus==1) printf("signature valid\n");
else if(authstatus==0) printf("invalid signature\n");
else printf("error at signature verification\n"); // -1
putchar('\n');
free(signed_msg);
free(signed_msg_);
DSA_free(dsakey);
//EVP_PKEY_free(privkey);
//netwcomm_cleanup();
return 0;
}