C library for CMS/X.509 manipulation - c

Some context: I have a PKCS #11-compliant cryptographic engine. This engine will be used to handle signed/enveloped data, i.e. verify the data's ECDSA/SHA1 signature, unwrap the symmetric key with RSAES-OAEP, and decrypt this data. This means the symmetric key will be wrapped with my engine's public key: hence I'd like the certificate for this public key to actually read "Subject Public Key Algorithm: RSAES-OAEP".
I'm looking for a C library which will let me manipulate objects comforming to the Cryptographic Message Syntax (CMS) and X.509 standards in the following way:
create a X.509 Certificate Signing Request (CSR), setting the Subject Public Key Algorithm to RSAES-OAEP
let me handle the signing part: my private key is only accessible via a PKCS #11 handle, so I need the library to give me the bytes to sign, and then let me set the CSR's ProofOfPossession field with what my crypto engine computed
export the complete CSR to something (DER or PEM)
create CMS structures to hold something like SignedData( EnvelopedData( stuff )). The library could handle the actual encryption/key wrapping/signature, or it could let some other software engine do it and just allow me to set the octet strings
let me easily parse back the message and recover those octet strings
meaning I want to open a DER/PEM file which contains this CMS message, and get the bytes for the signature, the wrapped key and the encrypted stuff, so that I can feed them to my PKCS #11 interface
Before anyone suggests OpenSSL's libcrypto, I've looked at it (looked as in, "spent the last week trying to understand how the structures work, how the ASN.1 representation works, how I can recover the bytes I'm interested in from OpenSSL's structures..."), and I have some issues with it (as of 1.0.1f):
(cf 1.) I cannot set the Subject Public Key Algorithm to RSAE-OAEP. Starting from demos/x509/mkreq.c, and going all the way back to the deep reaches of x509t.h's weird #define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) macros, I think I can affirm that X509_REQ_set_pubkey() cannot handle OAEP.
(cf 2.) Neither can the CMS part of the crypto lib, for that matter. cms_RecipientInfo_ktri_encrypt() calls EVP_PKEY_CTX_ctrl(), which I guess resolves to crypto/rsa/rsa_pmeth.c:pkey_rsa_ctrl(): when p2 is EVP_PKEY_CTRL_CMS_ENCRYPT, p2 is not parsed, so RSA padding is not set (if it turns out I'm wrong and I just cannot read code correctly, please tell me).
So while I'm glad this guy managed to make it "work like a charm", I cannot share his enthusiasm.
I guess for 2. I could use OpenSSL to create CMS blank structures, compute the future EnvelopedData content (ie stuff encrypted with a symmetric key + symmetric key wrapped with RSA OAEP), and stuff this content into the structures, bypassing CMS_encrypt() completely, before encapsulating into a SignedData (I'm assuming CMS_sign() will handle ECDSA/SHA1). As long as I don't want to use fancy parameters for OAEP (although this other guy managed to patch the lib to use OAEP with SHA-256).
But this might end up requiring a tad too much fiddling with OpenSSL's ASN.1 API. Hence my interrogation: does anyone know of a C library to build CMS structures and feed them the octet strings computed by some other engines? Also how to build certificates which read "THIS KEY IS MEANT TO BE USED WITH RSAES-OAEP".
I've looked at libksba and cryptlib and while I guess they could work, I cannot see how to use them yet (might have something to do with my eyes bleeding from staring at OpenSSL's code so much - I do not mean to say that OpenSSL's code is bad or anything, just that I've been looking at it hard, and the doc is slightly lacking).
Actually, I guess, I could drop the C requirement (mainly there because communicating with the crypto engine is done in PKCS #11/C). Here's what the library should be able to do:
build a CSR
... featuring "RSAES-OAEP" as Subject Public Key Algorithm
give me the bytes to sign for the Proof-of-Possession part
take the signature and output a complete X.509 CSR
parse a CMS structure
(SignedData) give me the bytes corresponding to the signedInfo->signature and encapsulatedContentInfo fields so that I can verify them with some other engine
(EnvelopedData) give me the bytes corresponding to the keyTransRecipientInfo->encryptedKey and encryptedContentInfo->encryptedContent fields so that I can unwrap/decrypt with some other engine
build a CMS structure, either...
letting some external engine set the fields mentioned above, and letting me specify the algorithms
actually implementing the algorithms, and building the CMS from just the data (... with RSAES-OAEP for key wrapping)
Right now I'm going with a "all-OpenSSL" approach, because I feel like I'm in too deep and should not start wandering somewhere else. If anybody has a better idea, I am all ears.
As for setting that subject public key algorithm... Well, either I'll just leave regular RSA and have my application "know" that wrapping is RSAES-OAEP, or... I don't know. And as for signing the request... is POP all that useful anyway?
(This is not a serious question)
NB: edited to remove the whole "I want my certificate to read OAEP", since I just found out about RFC 5756 (also found an interesting discussion from 2006 when this RFC was not out yet).

Here's what I managed to get working so far.
1. Building a CSR, signing it with some other engine
I mostly followed demos/x509/mqreq.c, with some twists.
(NB: error checking, fancy modulus length/label/subject DN generation/handling has been left out for brevity and focus on actual flow).
unsigned char* mod = NULL;
unsigned char* exp = NULL;
size_t mod_l = 0;
size_t exp_l = 0;
P11_handle h_key = P11_gen_rsa(&mod, &mod_l, &exp, &exp_l);
RSA* rsa = RSA_new();
rsa->n = BN_bin2bn(rsa_mod, rsa_mod_l, NULL);
rsa->e = BN_bin2bn(rsa_exp, rsa_exp_l, NULL);
EVP_PKEY* pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
X509_REQ* csr = X509_REQ_new();
X509_REQ_set_pubkey(csr, pkey);
/* Boring X509_NAME/X509_EXTENSION stuff */
X509_REQ_INFO* csr_req = csr->req_info;
unsigned char* pop_in = NULL;
size_t pop_in_l = ASN1_item_i2d((void*)csr_req, &pop_in,
ASN1_ITEM_rptr(X509_REQ_INFO));
unsigned char* sig = NULL;
size_t sig_l = 0;
P11_make_pop(SIGN_RSA_PKCS, DIGEST_SHA256,
pop_in, pop_in_l, &sig, &sig_l,
h_key);
/* Add signature to CSR (heavily inspired from ASN1_item_sign_ctx())
* (please don't ask about the flags) */
if (csr->signature->data != NULL) OPENSSL_free(csr->signature->data);
csr->signature->data = sig;
csr->signature->length = sig_l;
csr->signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
csr->signature->flags|= ASN1_STRING_FLAG_BITS_LEFT;
/* Add signature algorithm information to CSR */
int sig_algo_nid = 0;
OBJ_find_sigid_by_algs(&sig_algo_nid,
EVP_MD_nid(EVP_sha256()), EVP_PKEY_RSA);
X509_ALGOR_set0(csr->sig_alg, OBJ_nid2obj(sig_algo_nid),
V_ASN1_NULL, NULL));
After that, the X509_REQ structure is good for PEM export. openssl req -verify seems to validate the process, so as far as I'm concerned this works.
2. Building nested CMS structures (as in SignedData(EnvelopedData(Data)))
Finally got it, using 1.0.2 (any previous version would have needed patching or ASN.1-level parsing). Many thanks to Dr. Stephen Henson and Tom Francis for helping me with this via the mailing list.
/* Make EnvelopedData structure */
BIO* in = BIO_new_file(in_path, "rb");
int flags = CMS_BINARY | CMS_USE_KEYID | CMS_PARTIAL | CMS_KEY_PARAM;
CMS_ContentInfo* edata = CMS_encrypt(NULL, NULL, cipher, flags);
CMS_RecipientInfo* r_info = CMS_add1_recipient_cert(edata, r_cert, flags);
EVP_PKEY_CTX* wrap_ctx = CMS_RecipientInfo_get0_pkey_ctx(r_info);
EVP_PKEY_CTX_set_rsa_padding(wrap_ctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(wrap_ctx, EVP_sha256());
EVP_PKEY_CTX_set_rsa_mgf1_md(wrap_ctx, EVP_sha256());
EVP_PKEY_CTX_set0_rsa_oaep_label(wrap_ctx, oaep_label, oaep_label_l);
/* NB: oaep_label must be heap-allocated, and will be freed by OSSL */
CMS_final(edata, in, NULL, flags);
BIO* tmp = BIO_new(BIO_s_mem());
i2d_CMS_bio(tmp, edata);
/* Make SignedData structure */
flags|= CMS_NOSMIMECAP | CMS_NOCERTS;
flags&= ~(CMS_KEY_PARAM);
CMS_ContentInfo* sdata = CMS_sign(NULL, NULL, NULL, NULL, flags);
ASN1_OBJECT* ectype_edata = OBJ_nid2obj(NID_pkcs7_enveloped);
CMS_set1_eContentType(sdata, ectype_edata);
CMS_SignerInfo* s_info =
CMS_add1_signer(sdata, s_cert, s_key, NULL, flags);
CMS_SignerInfo_sign(s_info);
CMS_final(sdata, tmp, NULL, flags);
BIO* out = BIO_new_file(out_path, "wb");
i2d_CMS_bio(out, sdata);
BIO_flush(out);
3. Parsing the structure and getting the fields I need.
I basically wrote my own CMS parser. ASN.1 is actually simple to parse when you know the spec. I've tried compiling the ASN.1 modules in the RFC using some "ASN.1 to C structs" compilers but had no luck (they kept choking on the syntax).

Related

mbedtls: How to transfer and load public key as raw bytes

I want to use a public/private key pair (ECDSA using secp256r1 curve) to sign commands sent to an embedded device via BLE, and verify them on the device. This means sending the public key to the embedded device (during registration) and storing the public key on the device. When a command is received by the device, the public key is used to verify the signature with mbedtls.
To keep things simple and efficient, I thought it would be best to send and store the uncompressed 64 byte data from the public key (i.e. x and y co-ordinates).
I can generate a key pair and extract the 64 bytes of the public key in my Android app, and send these to the device using BLE.
However, I haven't found a good way to use this public key data to verify signatures with embedtls - i.e. to load the raw 64 bytes into a suitable mbedtls_ecp_keypair struct.
I have been able to do it with "mbedtls_ecp_point_read_string" as follows (error checking removed for brevity):
// public_key_data is buffer containing 64 bytes (32 bytes X, 32 bytes Y).
mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa);
mbedtls_ecp_keypair public_key;
mbedtls_ecp_keypair_init(&public_key);
mbedtls_ecp_point_init(&public_key.Q);
mbedtls_ecp_group_init(&public_key.grp);
mbedtls_ecp_group_load(&public_key.grp, MBEDTLS_ECP_DP_SECP256R1);
// Convert raw bytes of public key (public_key_data) to ASCII string (hex format).
// BytesToHexStr is C function to convert bytes to string:
char x_str[65]; // 2 x 32 bytes + 1 byte for terminating NUL
char y_str[65];
BytesToHexStr(public_key_data, x_str, ...);
BytesToHexStr(public_key_data + 32, y_str, ...);
// Get ECP point from string...
mbedtls_ecp_point_read_string(
&public_key.Q, // mbedtls_ecp_point *P,
16, // int radix,
x_str, // const char *x,
y_str // const char *y
);
mbedtls_ecdsa_from_keypair(&ecdsa, &public_key);
// Generate hash of message:
mbedtls_sha256_ret(message, message_size, hash, SHA_256);
// Verify signature:
int verify_result = mbedtls_ecdsa_read_signature(&ecdsa, hash, sizeof(hash), signature, signature_size);
// Check verify_result, clean up, etc.
However, this seems cumbersome.
I tried using the "mbedtls_ecp_point_read_binary" function with my raw public key, but it returned -20096 (MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE). The mbedtls documentation says "This function imports a point from unsigned binary data", but it doesn't give any details about what format the data is expected to be in.
Is there a better way to transfer / store / load ECDSA public key data with mbedtls?
I faced the exact same problem today.
Eventually figured out that mbedtls_ecp_point_read_binary expects binary data in uncompressed public key format, i.e 0x04 followed by X followed by Y.
If you've found this post for a similar but slightly different situation in that you are trying to use mbedtls_ecp_point_read_binary to read in your peer's public key (for ECDSA or ECDH key exchange for example), however your peer has only sent a compressed public key (33 bytes), there's a solution for this but it's limited to only a certain set of curves in mbedtls.
If you try mbedtls_ecp_point_read_binary to read in your peer's public key in compressed format you'll get a 0x4F80 (MBEDTLS_ERR_ECP_BAD_INPUT_DATA) error. The issue is exactly what #regnarts says (you need a decompressed key).
The challenge is that mbedtls doesn't support key decompression. Only tangentially related here but you can read into why that is here and here. Long story short, what emerged was a handy library (see link below) that correctly decompresses a key in binary format for a limited set of curves. Because it only supports those limited set of curves it wasn't incorporated into mbedtls, but it solved my problem so it's worth trying.
https://github.com/mwarning/mbedtls_ecp_compression

Decoder return of av_find_best_stream vs. avcodec_find_decoder

The docs for libav's av_find_best_stream function (libav 11.7, Windows, i686, GPL) specify a parameter that can be used to receive a pointer to an appropriate AVCodec:
decoder_ret - if non-NULL, returns the decoder for the selected stream
There is also the avcodec_find_decoder function which can find an AVCodec given an ID.
However, the official demuxing + decoding example uses av_find_best_stream to find a stream, but chooses to use avcodec_find_decoder to find the codec in lieu of av_find_best_stream's codec return parameter:
ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
...
stream_index = ret;
st = fmt_ctx->streams[stream_index];
...
/* find decoder for the stream */
dec = avcodec_find_decoder(st->codecpar->codec_id);
As opposed to something like:
ret = av_find_best_stream(fmt_ctx, type, -1, -1, &dec, 0);
My question is pretty straightforward: Is there a difference between using av_find_best_stream's return parameter vs. using avcodec_find_decoder to find the AVCodec?
The reason I ask is because the example chose to use avcodec_find_decoder rather than the seemingly more convenient return parameter, and I can't tell if the example did that for a specific reason or not. The documentation itself is a little spotty and disjoint, so it's hard to tell if things like this are done for a specific important reason or not. I can't tell if the example is implying that it "should" be done that way, or if the example author did it for some more arbitrary personal reason.
av_find_best_stream uses avcodec_find_decoder internally in pretty much the same way as in your code sample. However there is a change in av_find_best_stream behaviour when decoder is requested from it - namely, it will try to use avcodec_find_decoder on each candidate stream and if it fails then it will discard the candidate and move on to the next one. In the end it will return best stream together with its decoder. If decoder is not requested, it will just return best stream without checking if it can be decoded.
So if you just want to get single video/audio stream and you are not going to write some custom stream selection logic then I'd say there's no downside to using av_find_best_stream to get a decoder.

Reading and writing OpenSSL ECDSA keys to PEM file

I want to generate an ecdsa key pair and save it to PEM file. Here's the code that I generate the key.
#include <openssl/ec.h> // for EC_GROUP_new_by_curve_name, EC_GROUP_free, EC_KEY_new, EC_KEY_set_group, EC_KEY_generate_key, EC_KEY_free
#include <openssl/ecdsa.h> // for ECDSA_do_sign, ECDSA_do_verify
#include <openssl/obj_mac.h> // for NID_secp256k1
/*
* Function generate_eckey
* -----------------------
*
* This function generates an EC_Key object that stores the ECDSA key pair.
*
* return: ec key pair
*/
EC_KEY * generate_eckey() {
EC_KEY *eckey=EC_KEY_new();
EC_GROUP *ecgroup= EC_GROUP_new_by_curve_name(NID_secp256k1);
EC_KEY_set_group(eckey, ecgroup);
EC_KEY_generate_key(eckey);
return eckey;
}
int main() {
// generate a eckey used to produce signatures
EC_KEY *eckey = generate_eckey();
return 0;
}
Now I have this key pair that can be used to sign and verify messages. What I want to do is save the information to a file so next time I can simply load it and use it.
I want to know how can I write and load the keys to a PEM file? Does openssl have an existing function to do so? I have no preference whether the keys are encoded in any format, as long as after loading I can use it. Any example would be great.
I want to know how can I write and load the keys to a PEM file? Does openssl have an existing function to do so?
Yes, OpenSSL has existing functions. For ASN.1/DER, use d2i_ECPrivateKey and d2i_EC_PUBKEY; and for PEM use PEM_read_ECPrivateKey and PEM_read_EC_PUBKEY. The write functions are similar and documented in the man pages.
d2i_* is "DER to internal", and its used to read ASN.1/DER keys. The write functions use i2d_* and its "internal to DER". PEM does not use a cryptic prefix.
For an example of using d2i_* and PEM_* with RSA keys in a C++ program with the output, see Use OpenSSL RSA key with .Net. You can just swap-in your EC functions in place of the RSA ones.
EC_KEY * generate_eckey() {
EC_KEY *eckey=EC_KEY_new();
EC_GROUP *ecgroup= EC_GROUP_new_by_curve_name(NID_secp256k1);
EC_KEY_set_group(eckey, ecgroup);
EC_KEY_generate_key(eckey);
return eckey;
}
Related, when you write your EC keys, be sure to use a named curve by callingEC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE). If you don't then the keys could be of limited use. Also see Elliptic Curve Cryptography | Named Curves on the OpenSSL wiki.
Also, you are ignoring return values from functions like EC_KEY_new and EC_KEY_generate_key. You might want to rethink that strategy since those function can fail for non-obvious reasons, like a policy setting. Also see EC_KEY_new man pages.

App windows 8 hash md5

I need to calculate the md5 of a file saved locally in an windows8 app created in
javascript / html.
I need the md5 to compare it with an online file and see if the two objects are really the same.
What function should I use?
Here's the code I use to hash a string in MD5 using Windows.Security.Cryptography namespace:
var inputBuffer, outputBuffer, toHash, hashed,
hashProvider = Windows.Security.Cryptography.Core.HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.md5); // "open" an md5 hash provider
toHash = 'string'; // string to hash
inputBuffer = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(toHash, Windows.Security.Cryptography.BinaryStringEncoding.utf8); // convert string to binary
outputBuffer = hashProvider.hashData(inputBuffer); // hash the binary
hashed = Windows.Security.Cryptography.CryptographicBuffer.encodeToHexString(outputBuffer); // the hashed string
Now, all you need to do is to read the file in (see http://msdn.microsoft.com/en-us/library/windows/apps/hh464978.aspx). If reading the file into a buffer, then you wouldn't need the convertStringToBinary line.
The WinRT API provides SHA functionality in the Windows.Security.Cryptography.Core namespace, specifically through the static method HashAlgorithmProvider.openAlgorithm(Windows.Security.Cryptography.Certificates.HashAlgorithmNames.sha256).
This provides you with a HashAlgorithmProvider class that has methods like hashData.
Fin in this Link is all that's available in winjs in terms of cryptography.
And Here you can find an example on how to implement an MD5 calculator for a string, from there is a good start to make it work for a file.
Hope this helps.

How do I feed OpenSSL random data for use in ECDSA signing?

I want to feed OpenSSL specific data for use as random seed during the signing of data with an EC key. I'm doing this to compare my application with another reference one (closed source). That utility takes the file with private key, file with data to sign and file with random data as parameters.
I've got the generation of EC keys, and signing of data down, but can't compare the two applications since I have no common ground. OpenSSL generates random data used in signing the data (probably from /dev/random) and thus gives me a different signature every run.
I've tried RAND_clear() in combination with RAND_add(), but keep getting changing signatures. Either I don't understand the whole ECDSA concept, or I'm doing something wrong.
My second option for comparing the applications is to import the public key and verify the signature generated by the reference program. This is the better option, but I'm unable to import the given example public key (83 character hex string). EC_POINT_oct2point() keeps giving me null results.
Any help/pointers/references would be greatly appreciated.
char * key_as_binary_data; //369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702
int data_size; //Size of the key buffer
EC_POINT * ecpoint = NULL;
EC_GROUP * ecgroup = NULL;
EC_KEY * eckey = NULL;
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
int asn1_flag = OPENSSL_EC_NAMED_CURVE;
eckey = EC_KEY_new();
ecpoint = EC_POINT_new(ecgroup);
ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1"));
EC_GROUP_set_asn1_flag(ecgroup, asn1_flag);
EC_GROUP_set_point_conversion_form(ecgroup, form);
EC_KEY_set_group(eckey,ecgroup);
EC_KEY_generate_key(eckey);
//This gives me a null ecpoint
EC_POINT_oct2point(ecgroup,ecpoint,key_as_binary_data,data_size-1,ctx);
EC_KEY_set_public_key(eckey,ecpoint);
This is how you should go about loading that public key:
EC_KEY *key = NULL;
EC_POINT *pub_key;
const EC_GROUP *group;
SSL_library_init();
SSL_load_error_strings();
key = EC_KEY_new_by_curve_name(NID_sect163k1);
group = EC_KEY_get0_group(key);
pub_key = EC_POINT_new(group);
EC_POINT_hex2point(group,
"369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702", pub_key, NULL);
EC_KEY_set_public_key(key, pub_key);
if (!EC_KEY_check_key(key)) {
printf("EC_KEY_check_key failed:\n");
printf("%s\n",ERR_error_string(ERR_get_error(),NULL));
} else {
printf("Public key verified OK\n");
}
It seems to verify OK, so it should work for checking a signature.
I think your bug might have just been passing a NULL (in ecgroup) to EC_POINT_new().
The reason you get different results despite the fact that you are clearing the pool and resetting it is that by default OpenSSL's RAND implementation will hash the pid into the output block (precisely to ensure that even applications that use the same seed do not get the same PRNG output, since 99.9% of the time that happening is a Bad Thing).
In addition, even if this was not the case, it is unlikely that your reference application uses the same PRNG that OpenSSL uses to turn the seed file into a series of random bytes. (Unless your reference application actually uses OpenSSL as well, of course). What you would have to do is first figure out what kind of PRNG the reference app uses - this might be a standard PRNG design like the ones from X9.31 or FIPS-186, or might be something totally custom. Then reimplement that design for OpenSSL and plug it in via RAND_set_rand_method.
As to verification: it looks like you need to transpose the lines:
ecpoint = EC_POINT_new(ecgroup);
ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1"));
Otherwise ecpoint is set to NULL right from the start, and this causes EC_KEY_generate_key to fail, because the group is set to NULL. Quoting from openssl-0.9.8k's crypto/ec/ec_key.c:
if (!eckey || !eckey->group)
{
ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
You can control the random data that OpenSSL produces during signing by using the method:
ECDSA_SIG* ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey);
where kinv is the random number that is used during signing.
The signing procedure is purely to allow someone else to confirm that you signed it ie. it was your private key that was used to sign the message (or any data) without actually having your private key.
The algorithm is outlined on wikipedia Elliptic_Curve_DSA
Reading "Signature generation algorithm" it appears the random data is used to assist in the strength of the signature and to make it harder to attack to figure out the private key.
Therefore you should expect the signature to be different each time since this is not just simply a hash.
See the section "Signature verification algorithm" to see that the verification steps are the ones you wish to use to confirm that your openssl version is outputing valid signatures w.r.t. the ECDSA method and the closed source program.
I can't find the docs for RAND_clear, so can't comment why it's not resulting in reproducible random numbers.
But even if you get that done, what you want may not be possible. ECDSA signature generation requires choosing a random integer in a particular range. Two different implementations of the algorithm might have completely different ideas about how to generate such an integer from their entropy source. AFAIK the means of transforming bits of entropy into the required number is not part of the ECDSA algorithm.
So for example (very bad examples of course), one implementation might do this:
int random_number = rand() % n;
and another might do this:
int random_number = (rand() * n) / RAND_MAX;
So even if you give them the same seed data, you might still get different signatures from different implementations. All you can do is validate whether you have generated a valid signature.

Resources