How to get correct result from my RSA Sign? - rsa

I have written a piece of code to hash and rsa encrypt (somehow sign) a data sent to java card.
This is java card code:
public class HelloWorldApplet extends Applet {
final static byte APLET_CLA = (byte)0x80;
final static byte INITIALIZE = (byte)0x00;
final static byte SIGN = (byte)0x01;
final static byte HASHVERIFY = (byte)0x07;
final static byte GETHASH = (byte)0x08;
final static short SW_WRONG_DATA_LENGTH = 0x6300;
final static short SW_KEY_NOT_INITIALIZED = 0x6301;
final static short SW_KEY_IS_INITIALIZED = 0x6302;
final static short SW_KEY_IS_NOT_INITIALIZED = 0x6303;
final static short SW_INCORRECT_PARAMETER = 0x6304;
public static byte[] Message;
public static short message_len = 0;
public static short hashLen = 0;
public static short signLen = 0;
public static boolean key_initialization_flag256 = false;
public static boolean key_initialization_flag128 = false;
// use unpadded RSA cipher for signing
Cipher cipherRSA256 = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);
Cipher cipherRSA128 = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);
KeyPair rsaPair256 = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_2048);
KeyPair rsaPair128 = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_1024);
RSAPrivateCrtKey rsaKeyPriv256;
RSAPrivateCrtKey rsaKeyPriv128;
RSAPublicKey rsaKeyPub256;
RSAPublicKey rsaKeyPub128;
byte[] hashBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT);
byte[] signBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT);
byte[] dataBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT);
MessageDigest md = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
public static void install(byte[] bArray, short bOffset, byte bLength)
{
Message = new byte[256];
new HelloWorldApplet().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
}
public void process(APDU apdu)
{
if (selectingApplet())
{
return;
}
byte[] buffer = apdu.getBuffer();
if (buffer[ISO7816.OFFSET_CLA] == APPLET_CLA) {
switch (buffer[ISO7816.OFFSET_INS]) {
case INITIALIZE:
// generate a new key
initialize(apdu);
break;
case SIGN:
// sign a given incoming message
sign_message(apdu);
break;
case HASHVERIFY:
verify_hash(apdu);
break;
case GETHASH:
get_hash(apdu);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
} else {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
}
public void initialize(APDU apdu)
{
byte[] buffer = apdu.getBuffer();
switch(buffer[ISO7816.OFFSET_P1]) {
case 0x00: // gen 256 byte RSA key (P1=00)
if (key_initialization_flag256)
ISOException.throwIt(SW_KEY_IS_INITIALIZED);
rsaPair256.genKeyPair();
rsaKeyPriv256 = (RSAPrivateCrtKey) rsaPair256.getPrivate();
rsaKeyPub256 = (RSAPublicKey) rsaPair256.getPublic();
key_initialization_flag256 = true;
break;
case 0x01: // gen 128 byte RSA key (P1=01)
if (key_initialization_flag128)
ISOException.throwIt(SW_KEY_IS_INITIALIZED);
rsaPair128.genKeyPair();
rsaKeyPriv128 = (RSAPrivateCrtKey) rsaPair128.getPrivate();
rsaKeyPub128 = (RSAPublicKey) rsaPair128.getPublic();
key_initialization_flag128 = true;
break;
}
}
// P1=0 for modulus, P1=1 for exponent
private void getPublicRSA(APDU apdu)
{
byte[] buffer = apdu.getBuffer();
short length = 0;
switch (buffer[ISO7816.OFFSET_P1])
{
case 0x00: // 256 byte RSA (P1)
if (!key_initialization_flag256)
ISOException.throwIt(SW_KEY_IS_INITIALIZED);
switch (buffer[ISO7816.OFFSET_P2]) {
case 0x00: // get the modulus (P2)
length = rsaKeyPub256.getModulus(buffer, (short) 0);
break;
case 0x01: // get the exponent (P2)
length = rsaKeyPub256.getExponent(buffer, (short) 0);
break;
default:
ISOException.throwIt(SW_INCORRECT_PARAMETER);
break;
}
break;
case 0x01: // 128 byte RSA (P1)
if (!key_initialization_flag128)
ISOException.throwIt(SW_KEY_IS_INITIALIZED);
switch (buffer[ISO7816.OFFSET_P2]) {
case 0x00: // get the modulus (P2)
length = rsaKeyPub128.getModulus(buffer, (short) 0);
break;
case 0x01: // get the exponent (P2)
length = rsaKeyPub128.getExponent(buffer, (short) 0);
break;
default:
ISOException.throwIt(SW_INCORRECT_PARAMETER);
break;
}
break;
default:
ISOException.throwIt(SW_INCORRECT_PARAMETER);
}
apdu.setOutgoingAndSend((short) 0, length);
}
public void sign_message(APDU apdu)
{
byte[] buffer = apdu.getBuffer();
switch(message_len) {
case 256:
if(!key_initialization_flag256)
ISOException.throwIt(SW_KEY_IS_NOT_INITIALIZED);
cipherRSA256.init(rsaPair256.getPrivate(), Cipher.MODE_ENCRYPT);
Util.arrayCopyNonAtomic(Message, (short) 0, dataBuffer, (short) 0, message_len);
pkcs1_sha(dataBuffer, (short) 0, message_len, hashBuffer); // 32 Bytes
signLen = cipherRSA256.doFinal(hashBuffer, (short) 0, message_len, signBuffer, (short) 0); // 128 Bytes
Util.arrayCopy(signBuffer,(short)0,buffer,(short)0,signLen);
apdu.setOutgoingAndSend((short) 0, signLen);
break;
case 128:
if(!key_initialization_flag128)
ISOException.throwIt(SW_KEY_IS_NOT_INITIALIZED);
cipherRSA128.init(rsaPair128.getPrivate(), Cipher.MODE_ENCRYPT);
Util.arrayCopyNonAtomic(Message, (short) 0, dataBuffer, (short) 0, message_len);
pkcs1_sha(dataBuffer, (short) 0, message_len, hashBuffer); // 32 Bytes
signLen = cipherRSA128.doFinal(hashBuffer, (short) 0, message_len, signBuffer, (short) 0); // 128 Bytes
Util.arrayCopy(signBuffer, (short) 0, buffer, (short) 0, signLen);
apdu.setOutgoingAndSend((short) 0, signLen);
break;
default:
ISOException.throwIt(SW_WRONG_DATA_LENGTH);
break;
}
}
public void verify_hash(APDU apdu) {
byte[] buffer = apdu.getBuffer();
switch(message_len) {
case 256:
if(!key_initialization_flag256)
ISOException.throwIt(SW_KEY_IS_INITIALIZED);
cipherRSA256.init(rsaPair256.getPublic(), Cipher.MODE_DECRYPT);
hashLen = cipherRSA256.doFinal(signBuffer, (short) 0, message_len, buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, message_len);
break;
case 128:
if(!key_initialization_flag128)
ISOException.throwIt(SW_KEY_IS_INITIALIZED);
cipherRSA128.init(rsaPair128.getPublic(), Cipher.MODE_DECRYPT);
hashLen = cipherRSA128.doFinal(signBuffer, (short) 0, message_len, buffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, message_len);
break;
default:
ISOException.throwIt(SW_WRONG_DATA_LENGTH);
break;
}
}
public void get_hash(APDU apdu) {
byte[] buffer = apdu.getBuffer();
Util.arrayCopy(hashBuffer,(short)0,buffer,(short)0,message_len);
apdu.setOutgoingAndSend((short)0,message_len);
}
// this function will leave tempBuffer with the data to be signed
public void pkcs1_sha(byte[] toSign, short bOffset, short bLength,byte[] out)
{
md.reset();
hashLen = md.doFinal(toSign, bOffset, bLength, out, (short) 0);
}
}
the problem is, when I execute sign, verify and get hash commands, I desire to get same answers from verify and get hash. for some data the card answers correctly:
mode_211
enable_trace
establish_context
enable_trace
enable_timer
card_connect
command time: 593 ms
select -AID E0E1E2E3E4E501
Command --> 00A4040007E0E1E2E3E4E501
Wrapped command --> 00A4040007E0E1E2E3E4E501
Response <-- 9000
command time: 31 ms
send_apdu -sc 1 -APDU 8000010000 // Gen RSA Key 128
Command --> 8000010000
Wrapped command --> 8000010000
Response <-- 6302
send_APDU() returns 0x80206302 (Unknown ISO7816 error: 0x6302)
command time: 0 ms
send_apdu -sc 1 -APDU 80040000802EEEEFF1115D0B637ED81CE45EA86984E37521409EB67A7D
9E7DE88CF3BDC693B2B4F05748F9E705B2FE1C1D8CB9288B32D06952B6193935DD14FF9C89B9860B
0B31B9BA3C4130A4CC1CEC5CE430A784525B10706EC971C25B4C45CA3C9D98ECDB0825DADB499F31
36CB7322DFC44F4DAD71133CA894A14446416021684B9029
Command --> 80040000802EEEEFF1115D0B637ED81CE45EA86984E37521409EB67A7D9E7DE88CF3
BDC693B2B4F05748F9E705B2FE1C1D8CB9288B32D06952B6193935DD14FF9C89B9860B0B31B9BA3C
4130A4CC1CEC5CE430A784525B10706EC971C25B4C45CA3C9D98ECDB0825DADB499F3136CB7322DF
C44F4DAD71133CA894A14446416021684B9029
Wrapped command --> 80040000802EEEEFF1115D0B637ED81CE45EA86984E37521409EB67A7D9E
7DE88CF3BDC693B2B4F05748F9E705B2FE1C1D8CB9288B32D06952B6193935DD14FF9C89B9860B0B
31B9BA3C4130A4CC1CEC5CE430A784525B10706EC971C25B4C45CA3C9D98ECDB0825DADB499F3136
CB7322DFC44F4DAD71133CA894A14446416021684B9029
Response <-- 9000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 78 ms
send_apdu -sc 1 -APDU 8001000000 // Sign Message
Command --> 8001000000
Wrapped command --> 8001000000
Response <-- BF9E0C7BE366F6E9B2E78A8E7E101F8BFEDB3497AE68A7B8FCCA158DBDB937E6F62
76971AC7BF2B96F4258D4745719CBC93DEEDD344B512BCB1B8D6105837FB2C5F983C92F01FF0D8B5
3B009DA8EB76124EB4BFE24D598144A6726926A2A84E7F0C8FD00CE13121CDF68A3B87D6DCD06ED4
6EB56DE0E073B3BDBF37EC9934BCD9000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 203 ms
send_apdu -sc 1 -APDU 8008000000 // get hash
Command --> 8008000000
Wrapped command --> 8008000000
Response <-- 0BDE2856A3EC1083EBE56E8FCC7294ED06A7B63633C438A6CCB3C3B1D1C88811000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000009000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 47 ms
send_apdu -sc 1 -APDU 8007000000 // verify hash
Command --> 8007000000
Wrapped command --> 8007000000
Response <-- 0BDE2856A3EC1083EBE56E8FCC7294ED06A7B63633C438A6CCB3C3B1D1C88811000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000009000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 78 ms
card_disconnect
command time: 203 ms
release_context
command time: 0 ms
but for some other data, I get incorrect respond from card and I don't know why this happens. here is the second data answering incorrectly:
mode_211
enable_trace
establish_context
enable_trace
enable_timer
card_connect
command time: 577 ms
select -AID E0E1E2E3E4E501
Command --> 00A4040007E0E1E2E3E4E501
Wrapped command --> 00A4040007E0E1E2E3E4E501
Response <-- 9000
command time: 32 ms
send_apdu -sc 1 -APDU 8000010000 // Gen RSA Key 128
Command --> 8000010000
Wrapped command --> 8000010000
Response <-- 6302
send_APDU() returns 0x80206302 (Unknown ISO7816 error: 0x6302)
command time: 15 ms
send_apdu -sc 1 -APDU 8004000080335BE314CBC5C739DB41CCDD8FD0F53BB8F80E57DD3C18A9
091A715347BAFC5FD912A8973389BDFF05CF50A6E1B4716969A2C828A924D399D0A6A93DB0427666
7C9B623065D13192E5F372C8584A7111E74FC61923E1C1353DD1AE7D18991BEB3D83C49E6B756ABC
3359F9920E10BBEA24A999FB3E9A0CC1AC07E5C368F463DF
Command --> 8004000080335BE314CBC5C739DB41CCDD8FD0F53BB8F80E57DD3C18A9091A715347
BAFC5FD912A8973389BDFF05CF50A6E1B4716969A2C828A924D399D0A6A93DB04276667C9B623065
D13192E5F372C8584A7111E74FC61923E1C1353DD1AE7D18991BEB3D83C49E6B756ABC3359F9920E
10BBEA24A999FB3E9A0CC1AC07E5C368F463DF
Wrapped command --> 8004000080335BE314CBC5C739DB41CCDD8FD0F53BB8F80E57DD3C18A909
1A715347BAFC5FD912A8973389BDFF05CF50A6E1B4716969A2C828A924D399D0A6A93DB04276667C
9B623065D13192E5F372C8584A7111E74FC61923E1C1353DD1AE7D18991BEB3D83C49E6B756ABC33
59F9920E10BBEA24A999FB3E9A0CC1AC07E5C368F463DF
Response <-- 9000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 63 ms
send_apdu -sc 1 -APDU 8001000000 // Sign Message
Command --> 8001000000
Wrapped command --> 8001000000
Response <-- 9581924BA1F374489F83845FEEB7D71D71D3240C915CB1462434230982CA87A8AF3
0C2A716127C184E5DBB9EFF890A74A67967AC3EFE7E03FB433A3E52989459FDEF2CA8C19CD7BCD98
16434C4D84CF639F1D542F50B19BB56251BEA965F88168803F98906567CF1C2C6CE8B38999E16C50
49E2329F13156FA964F7477C07EF79000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 202 ms
send_apdu -sc 1 -APDU 8008000000 // get hash
Command --> 8008000000
Wrapped command --> 8008000000
Response <-- D9FE50E885FA4F2F85C70DC66FF42B5ABFAFB81820BF66F1967CB33D6E08AAE6000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000009000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 47 ms
send_apdu -sc 1 -APDU 8007000000 // verify hash
Command --> 8007000000
Wrapped command --> 8007000000
Response <-- 13AD6610CA13A7064193753BE50F268EC3F0D0AE8A5F079C0D40548835EAB0E9267
63B8EC02435CE8E126A4C97643D6BD2051E146CE353D351FF5FC58C0D2AD8BC5ADB40067F807EFE1
B2E1A37E027E6F50BA82DCE55DC37584F5941B6F29439234D97BE7612B03987E99C1F9F9A5A3B949
1E9758ECC7E02767D76B7C6C7A0B99000
send_APDU() returns 0x80209000 (9000: Success. No error.)
command time: 78 ms
card_disconnect
command time: 203 ms
release_context
command time: 0 ms
I will be so thankful if anyone can give me a hint or has had the same experience!!!

Your hash is placed at the most significant end of the value, as RSA uses big endian encoding. This means that the value may be returned mod N (the modulus), which will result in a different value than that you put in.
Place the hash at the least significant end of the message and your code should run.
Notes:
RSA without padding is not secure;
Signature generation is not the same as encrypting a hash value with a private key if you consider padding, side channel attacks, performance etc. etc. etc..

Related

Segmentation Fault in EVP_DigestFinal_ex -> SHA256_Final due to NULL algctx

using Linux (ubuntu 20.04) machine, openssl 3.0.7 is installed , running a sample code for signing.
we followed below procedure for signing. getting segmentation fault in EVP_DigestFinal_ex.
segmentation fault is happening due to mdctx->algctx=0x0. while debugging the code mdctx->algctx is updated in EVP_DigestInit_ex but latter it was freed in EVP_DigestSignInit. not sure what we are missing and how to update mdctx->algctx to avoid the crash.
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
EVP_PKEY *pkey = NULL;
generate_key(){
EVP_PKEY_CTX *ctx=NULL;
pkey=EVP_PKEY_new();
ctx=EVP_PKEY_CTX_new(pkey,NULL);
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx)
printf(" key gen failed");
if (EVP_PKEY_keygen_init(ctx) <= 0)
printf(" key gen failed");
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 512) <= 0)
printf(" key gen failed");
/* Generate key */
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
printf(" key gen failed");
}
int main(int argc, char *argv[])
{
EVP_MD_CTX *mdctx;
const EVP_MD *m_md;
const EVP_MD *md;
EVP_PKEY *m_key;
EVP_PKEY *ed_pkey = NULL;
EVP_PKEY_CTX *ed_pctx = NULL;
// OSSL_PROVIDER *default;
size_t sign_len = 0;
u_int8_t m_sign_buf[2048];
int ret = 0;
char mess1[] = "Test Message\n";
char mess2[] = "Hello World\n";
unsigned char *outdigest = NULL;
unsigned int md_len = 0, i;
printf("args : %s\n",argv[1]);
//default = OSSL_PROVIDE_load(NULL, "default");
//md = EVP_get_digestbyname("SHA256");
//md = EVP_sha256();
md = EVP_MD_fetch(NULL, "SHA256", NULL); //;
if (md == NULL) {
printf("Unknown message digest %s\n", argv[1]);
exit(1);
}
generate_key();
printf("value of md %s\n",md);
mdctx = EVP_MD_CTX_new();
if((EVP_DigestInit_ex(mdctx, md, NULL)) != 1)
printf("EVP_DigestInit_ex failed \n");
if((EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey)) != 1)
printf("EVP_DigestSignInit failed \n");
if((EVP_DigestSignUpdate(mdctx, mess1, strlen(mess1))) != 1)
printf("EVP_DigestSignUpdate failed \n");
//EVP_DigestUpdate(mdctx, mess2, strlen(mess2));
if((EVP_DigestSignFinal(mdctx, (u_int8_t*)NULL, &sign_len)) != 1)
printf("EVP_DigestSignFinal failed \n");
if((EVP_DigestSignFinal(mdctx, m_sign_buf, &sign_len)) != 1)
printf("EVP_DigestSignFinal 2 failed \n");
/* Allocate the output buffer */
outdigest = OPENSSL_malloc(EVP_MD_get_size(md));
if (outdigest == NULL)
printf("outdigest failed \n");
if((EVP_DigestFinal_ex(mdctx, outdigest, &md_len)) != 1)
printf("EVP_DigestFinal_ex failed \n");
EVP_MD_CTX_free(mdctx);
/* Print out the digest result */
BIO_dump_fp(stdout, outdigest, &md_len);
exit(0);
}
`
```
Thanks,
while debugging the code mdctx->algctx is updated in EVP_DigestInit_ex but latter it was freed in EVP_DigestSignInit. not sure what we are missing and how to update mdctx->algctx to avoid the crash.
CRASH Info:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7d99422 in SHA256_Final (md=0x5555555a88d0 "\250UUU\005", c=0x0)
    at ../openssl-3.0.7/include/crypto/md32_common.h:194
194         size_t n = c->num;
(gdb) bt
#0  0x00007ffff7d99422 in SHA256_Final (md=0x5555555a88d0 "\250UUU\005", c=0x0)
    at ../openssl-3.0.7/include/crypto/md32_common.h:194
#1  0x00007ffff7e2628c in sha256_internal_final (ctx=0x0, out=0x5555555a88d0 "\250UUU\005", outl=0x7fffffffda98,
    outsz=32) at ../openssl-3.0.7/providers/implementations/digests/sha2_prov.c:72
#2  0x00007ffff7cbadf6 in EVP_DigestFinal_ex (ctx=0x555555580d80, md=0x5555555a88d0 "\250UUU\005",
    isize=0x7fffffffdad8) at ../openssl-3.0.7/crypto/evp/digest.c:446
#3  0x000055555555575f in main (argc=1, argv=0x7fffffffe458) at test2.c:90

OpenSSL: how to get x509 -subject_hash "manually"?

I'm trying to get the same result as
openssl X509 -in certificate.pem -subject_hash
without using the function directly but instead by extracting the cerrtificate name and building the propper canonical representation to then take the sha-1 hash from. Is this possible? Something like
openssl x509 -in certificate.pem -subject -noout -nameopt dn_rev -nameopt RFC2253 | tr '[:upper:]' '[:lower:]' | openssl dgst -sha1 -binary | xxd -p
and then truncating the hash to 4bytes or so... so far I didn't get it though
$ openssl x509 -in .pem -subject_hash -noout
cc952886
$openssl x509 -in certificate.pem -subject -noout -nameopt RFC2253 | tr '[:upper:]' '[:lower:]' | openssl dgst -sha1 -binary | xxd -p
0b6a015b2a7ed2a5f3695f1d46a0c20006de300a
The respective c code is here: https://github.com/openssl/openssl/blob/d53b437f9992f974c1623e9b9b9bdf053aefbcc3/crypto/x509/x509_cmp.c#L261
unsigned long X509_NAME_hash_ex(const X509_NAME *x, OSSL_LIB_CTX *libctx,
const char *propq, int *ok)
{
unsigned long ret = 0;
unsigned char md[SHA_DIGEST_LENGTH];
EVP_MD *sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
/* Make sure X509_NAME structure contains valid cached encoding */
i2d_X509_NAME(x, NULL);
if (ok != NULL)
*ok = 0;
if (sha1 != NULL
&& EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, sha1, NULL)) {
ret = (((unsigned long)md[0]) | ((unsigned long)md[1] << 8L) |
((unsigned long)md[2] << 16L) | ((unsigned long)md[3] << 24L)
) & 0xffffffffL;
if (ok != NULL)
*ok = 1;
}
EVP_MD_free(sha1);
return ret;
}
and the canonical representation of the name is set here: https://github.com/openssl/openssl/blob/256d41d4371720ccfe1a4fead6bd28ed5071bcdd/crypto/x509/x_name.c#L303
/*
* This function generates the canonical encoding of the Name structure. In
* it all strings are converted to UTF8, leading, trailing and multiple
* spaces collapsed, converted to lower case and the leading SEQUENCE header
* removed. In future we could also normalize the UTF8 too. By doing this
* comparison of Name structures can be rapidly performed by just using
* memcmp() of the canonical encoding. By omitting the leading SEQUENCE name
* constraints of type dirName can also be checked with a simple memcmp().
*/
static int x509_name_canon(X509_NAME *a)
{
unsigned char *p;
STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname;
STACK_OF(X509_NAME_ENTRY) *entries = NULL;
X509_NAME_ENTRY *entry, *tmpentry = NULL;
int i, set = -1, ret = 0, len;
OPENSSL_free(a->canon_enc);
a->canon_enc = NULL;
/* Special case: empty X509_NAME => null encoding */
if (sk_X509_NAME_ENTRY_num(a->entries) == 0) {
a->canon_enclen = 0;
return 1;
}
intname = sk_STACK_OF_X509_NAME_ENTRY_new_null();
if (intname == NULL) {
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
entry = sk_X509_NAME_ENTRY_value(a->entries, i);
if (entry->set != set) {
entries = sk_X509_NAME_ENTRY_new_null();
if (entries == NULL)
goto err;
if (!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries)) {
sk_X509_NAME_ENTRY_free(entries);
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
set = entry->set;
}
tmpentry = X509_NAME_ENTRY_new();
if (tmpentry == NULL) {
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
tmpentry->object = OBJ_dup(entry->object);
if (tmpentry->object == NULL) {
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!asn1_string_canon(tmpentry->value, entry->value))
goto err;
if (!sk_X509_NAME_ENTRY_push(entries, tmpentry)) {
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
tmpentry = NULL;
}
/* Finally generate encoding */
len = i2d_name_canon(intname, NULL);
if (len < 0)
goto err;
a->canon_enclen = len;
p = OPENSSL_malloc(a->canon_enclen);
if (p == NULL) {
ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE);
goto err;
}
a->canon_enc = p;
i2d_name_canon(intname, &p);
ret = 1;
err:
X509_NAME_ENTRY_free(tmpentry);
sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname,
local_sk_X509_NAME_ENTRY_pop_free);
return ret;
}
Possibly, but you need to know all the Object Ids (OIDs) of all the relative Distinguished Name components (RDNs). e.g. CN=2.5.4.2 and then the ASN1 encoding. You need to rebuild the binary ASN1 blob then take the sha1 digest then take the first 4 bytes of that in reverse order.
I've created a bash script which uses the nameopts to get the subject in as close to ASN1 encoding as possible and also the OIDs. Then I've mashed all that together. https://github.com/nimpo/hash-bash-ssl

Running WebServerSecure and PubSubClient on ESP8266

I wrote a sketch for ESP8266. This sketch reads some sensor data and published it via MQTT. In addition I want to let a Web server provide the same data as HTML, or JSON web service.
The MQTT publish is triggered via a TaskScheduler timer.
Both functions, MQTT and Web server, work for itself, but sadly not together. Here's a simplified sketch:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServerSecure.h>
#include <PubSubClient.h>
#include <TaskScheduler.h>
#include <My_WLAN.h> // provices connection to local WLAN and network settings
const char DNS_NAME[] = "myserver.local";
const int HTTPS_PORT = 443; // HTTPS
const char MQTT_SVR[] = "myserver.local";
const unsigned int MQTT_PORT = 8883; // MQTTS
WiFiClientSecure wifiClient;
PubSubClient mqttClient(wifiClient); // MQTT client instance
ESP8266WebServerSecure server(HTTPS_PORT); // web server instance
void t1Callback(void); // callback method prototypes
Task t1(60000, TASK_FOREVER, &t1Callback); // main loop task
Scheduler timer; // task scheduler
static const uint8_t SVR_FINGERPRINT[20] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20 };
static const char deviceCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[... certificate ...]
-----END CERTIFICATE-----
)EOF";
static const char deviceKey[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
[... key ...]
-----END RSA PRIVATE KEY-----
)EOF";
/* *****************************
MQTT_connect
* *****************************/
void MQTT_connect()
{
int attempt = 0;
/* loop until reconnected */
while (!mqttClient.connected() && attempt < 10) {
attempt++;
Serial.print("Attempting MQTT connection ("); Serial.print(attempt); Serial.print(")...");
mqttClient.setServer(MQTT_SVR, MQTT_PORT);
if (mqttClient.connect(DNS_NAME)) {
Serial.println("success");
} else {
Serial.print("failed, status code = "); Serial.print(mqttClient.state());
Serial.println(". - Try again in 5 seconds...");
delay(5000);
}
}
}
/* *****************************
Web Server handleRoot
* *****************************/
void handleRoot() {
digitalWrite(LED_BUILTIN, LOW); // on
Serial.println("WebServer ROOT");
server.send(200, "text/html", "WebServer ROOT");
digitalWrite(LED_BUILTIN, HIGH); // off
}
/* *****************************
Web Server handleNotFound
* *****************************/
void handleNotFound() {
digitalWrite(LED_BUILTIN, LOW); // on
String message = "File not found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(LED_BUILTIN, HIGH); // off
}
/* *************************
MQTT_publish_something
* *************************/
void MQTT_publish_something() {
digitalWrite(LED_BUILTIN, LOW); // on
char payload[30] = "some_payload_data";
if (!mqttClient.publish("MQTT/Test", payload, true)) { // retain message
Serial.println("MQTT message lost!");
}
digitalWrite(LED_BUILTIN, HIGH); // off
}
/* *************************
t1: main timer (callback)
* *************************/
void t1Callback() {
my.WiFi_connect(); // check and re-connect to WLAN (in My_WLAN.h)
if (WiFi.status() == WL_CONNECTED) {
MQTT_connect();
MQTT_publish_something();
}
}
/* *************************
setup
* *************************/
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // internal LED
digitalWrite(LED_BUILTIN, HIGH); // off
/* -----------------------
open Serial |
----------------------- */
Serial.begin(74880);
while (!Serial); // wait for Serial being ready
/* -----------------------
connect to WLAN |
----------------------- */
my.WiFi_connect(); // this is connecting to WLAN & error handling (in My_WLAN.h)
wifiClient.setFingerprint(SVR_FINGERPRINT);
/* -----------------------
set mDNS |
----------------------- */
if (MDNS.begin(DNS_NAME)) {
Serial.printf("mDNS responder started for %s\n", DNS_NAME);
MDNS.addService("https", "tcp", HTTPS_PORT); // add service to MDNS-SD
MDNS.addService("mqtt", "tcp", MQTT_PORT);
} else
Serial.println("Error setting up mDNS responder!");
/* -----------------------
start HTTPS server |
----------------------- */
server.getServer().setRSACert(new X509List(deviceCert), new PrivateKey(deviceKey));
server.on("/", handleRoot); // standard HTML root
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTPS server started.");
Serial.println();
/* -----------------------
start timer |
----------------------- */
timer.init();
timer.addTask(t1);
// line 177:
timer.enableAll();
}
void loop() {
MDNS.update();
// line 184:
server.handleClient();
mqttClient.loop();
timer.execute();
}
Running MQTT only works fine and publishes data (I use the mosquitto broker).
Running the Web server (https://...) works fine as well, if commenting out line 177 (so MQTT does not get triggered).
With both functions active, as soon as the first MQTT message had been sent, the web server does not answer any more. I get PR_END_OF_FILE_ERROR in FF and ERR_CONNECTION_CLOSED in Chrome.
I guess, that these libraries somehow mess with each other, or that something confuses with the certificates. However, the fingerprint belongs to the server running mosquitto, while the X509 certificate belongs to the web server running on the ESP8266. These are two different machines and have nothing to do with each other.
Any idea welcome.
I suspect both libraries use port 443, and you can only have one listener on a given port. I've tried creating a BearSSL::ESP8266WebServerSecure object with alternate ports, such as 80 and 8443 but can't get them to work. Worse, there doesn't seem to be a way to stop a listener once a BearSSL::ESP8266WebServerSecure object has started, so it can't be released for later reuse.
I ended up using HTTP to get WiFi credentials, then HTTPS from there on out. Not a very satisfactory solution but it works.
Update: I was able to run a provisioning server on port 443, stop it by calling
BearSSL::ESP8266WebServerSecure provisioningServer(443);
BearSSL::ESP8266WebServerSecure server(443);
provisioningServer.close();
provisioningServer.~ESP8266WebServerSecure(); // note: cannot use TLS on both servers without this line
After calling the provisioning server's destructor I was able to start my server on port 443.

modbus_read_register - Error connection timed out

We are using libmodbus library to read register values from energy meter EM6400 which supports Modbus over RTU. We are facing the following two issues.
1) We are facing an issue with modbus_read_registers API, this API returns -1 and the error message is:
ERROR Connection timed out: select.
After debugging the library, we found this issue is due to the echo of request bytes in the response message.
read() API call in _modbus_rtu_recv returns request bytes first followed by response bytes. As a result, length_to_read is calculated in compute_data_length_after_meta() based on the request bytes instead of response bytes (which contains the number of bytes read) and connection timed out issue occurs.
We tried to use both 3.0.6 and 3.1.2 libmodbus versions but same issue occurs in both the versions.
2) modbus_rtu_set_serial_mode (ctx, MODBUS_RTU_RS485) returns "BAD file descriptor".
Please confirm if there is any API call missing or any parameter is not set correctly.
Our sample code to read register value is as follows.
int main()
{
modbus_t *ctx;
uint16_t tab_reg[2] = {0,0};
float avgVLL = -1;;
int res = 0;
int rc;
int i;
struct timeval response_timeout;
uint32_t tv_sec = 0;
uint32_t tv_usec = 0;
response_timeout.tv_sec = 5;
response_timeout.tv_usec = 0;
ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'E', 8, 1);
if (NULL == ctx)
{
printf("Unable to create libmodbus context\n");
res = 1;
}
else
{
printf("created libmodbus context\n");
modbus_set_debug(ctx, TRUE);
//modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK |MODBUS_ERROR_RECOVERY_PROTOCOL);
rc = modbus_set_slave(ctx, 1);
printf("modbus_set_slave return: %d\n",rc);
if (rc != 0)
{
printf("modbus_set_slave: %s \n",modbus_strerror(errno));
}
/* Commented - Giving 'Bad File Descriptor' issue
rc = modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
printf("modbus_rtu_set_serial_mode: %d \n",rc);
if (rc != 0)
{
printf("modbus_rtu_set_serial_mode: %s \n",modbus_strerror(errno));
}
*/
// This code is for version 3.0.6
modbus_get_response_timeout(ctx, &response_timeout);
printf("Default response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );
response_timeout.tv_sec = 60;
response_timeout.tv_usec = 0;
modbus_set_response_timeout(ctx, &response_timeout);
modbus_get_response_timeout(ctx, &response_timeout);
printf("Set response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );
/* This code is for version 3.1.2
modbus_get_response_timeout(ctx, &tv_sec, &tv_usec);
printf("Default response timeout:%d sec %d usec \n",tv_sec,tv_usec );
tv_sec = 60;
tv_usec = 0;
modbus_set_response_timeout(ctx, tv_sec,tv_usec);
modbus_get_response_timeout(ctx, &tv_sec, &tv_usec);
printf("Set response timeout:%d sec %d usec \n",tv_sec,tv_usec );
*/
rc = modbus_connect(ctx);
printf("modbus_connect: %d \n",rc);
if (rc == -1) {
printf("Connection failed: %s\n", modbus_strerror(errno));
res = 1;
}
rc = modbus_read_registers(ctx, 3908, 2, tab_reg);
printf("modbus_read_registers: %d \n",rc);
if (rc == -1) {
printf("Read registers failed: %s\n", modbus_strerror(errno));
res = 1;
}
for (i=0; i < 2; i++) {
printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}
avgVLL = modbus_get_float(tab_reg);
printf("Average Line to Line Voltage = %f\n", avgVLL);
modbus_close(ctx);
modbus_free(ctx);
}
}
Output of this sample is as follows:
created libmodbus context
modbus_set_slave return: 0
modbus_rtu_set_serial_mode: -1
modbus_rtu_set_serial_mode: Bad file descriptor
Default response timeout:0 sec 500000 usec
Set response timeout:60 sec 0 usec
Opening /dev/ttyUSB0 at 19200 bauds (E, 8, 1)
modbus_connect: 0
[01][03][0F][44][00][02][87][0A]
Waiting for a confirmation...
ERROR Connection timed out: select
<01><03><0F><44><00><02><87><0A><01><03><04><C4><5F><43><D4><C6><7E>modbus_read_registers: -1
Read registers failed: Connection timed out
reg[0]=0 (0x0)
reg[1]=0 (0x0)
Average Line to Line Voltage = 0.000000
Issue 1) is probably a hardware issue, with "local echo" enabled in your RS-485 adapter. Local echo is sometimes used to confirm sending of data bytes on the bus. You need to disable it, or find another RS-485 adapter.
I have written about this in the documentation of my MinimalModbus Python library: Local Echo
It lists a few common ways to disable local echo in RS-485 adapters.

Connect with DHCP server and get IP address

I want to get a IP address from DHCP server to my PIC 18F4520 device, and I used mikroc SPI Ethernet Library to program my PIC. I made a code and it is not working. I want to get IP address and display it on a LCD.Can any one help me how to do that?
#include "__EthEnc28j60.h"
#include "__EthEnc28j60Private.h"
// LCD module connections
sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections
/*// SD module connections
sbit Mmc_Chip_Select at LATC0_bit; // for writing to output pin always use latch
(PIC18 family)
sbit Mmc_Chip_Select_Direction at TRISC0_bit;
// End SD module connections*/
//ENC28j60 connection
sbit SPI_Ethernet_CS at LATC1_bit;
sbit SPI_Ethernet_Rst at LATC0_bit;
sbit SPI_Ethernet_CS_Direction at TRISC1_bit;
sbit SPI_Ethernet_Rst_Direction at TRISC0_bit;
//End ENC28j60 connection
const char httpHeader[] = "HTTP/1.1 200 OK\nContent-type: "; // HTTP header
const char httpMimeTypeHTML[] = "text/html\n\n"; // HTML MIME type
const char httpMimeTypeScript[] = "text/plain\n\n"; // TEXT MIME type
// default html page
char indexPage[] =
"<html><head><title>mikroElektronika</title></head><body>\
<h3 align=center>MikroElektronika Home Automatization System</h3>\
<form name=\"input\" action=\"/\" method=\"get\">\
<table align=center width=200 bgcolor=#4974E2 border=2><tr>\
<td align=center colspan=2><font size=4 color=white><b>Heat Control</b></font>\
</td></tr><tr><td align=center bgcolor=#4974E2><input name=\"tst1\" width=60 \
type=\"submit\" value=\"ON\"></td><td align=center bgcolor=#FFFF00>\
<input name=\"tst2\" type=\"submit\" value=\"OFF\"></td></tr></table>\
</form></body></html>";
// network parameters
char myMacAddr[6] = {0x00, 0x14, 0xA5, 0x76, 0x19, 0x3f}; // my MAC address
char myIpAddr[4] = {0, 0, 0, 0}; // my IP address
unsigned char getRequest[20]; // HTTP request buffer
unsigned int SPI_Ethernet_UserTCP(unsigned char *remoteHost, unsigned int remotePort,
unsigned int localPort, unsigned int reqLength, TEthPktFlags *flags)
{
unsigned int len; // my reply length
if(localPort != 80) return(0); // I listen only to web request on port 80
// get 10 first bytes only of the request, the rest does not matter here
for(len = 0 ; len < 15 ; len++) getRequest[len] = SPI_Ethernet_getByte();
getRequest[len] = 0;
if(memcmp(getRequest, "GET /", 5)) return(0); // only GET method
if(!memcmp(getRequest+11, "ON", 2)) // do we have ON command
PORTB.F0 = 1; // set PORTB bit0
else
if(!memcmp(getRequest+11, "OFF", 3)) // do we have OFF command
PORTB.F0 = 0; // clear PORTB bit0
if (PORTB.F0)
{
memcpy(indexPage+340, "#FFFF00", 6); // highlight (yellow) ON
memcpy(indexPage+431, "#4974E2", 6); // clear OFF
}
else
{
memcpy(indexPage+340, "#4974E2", 6); // clear ON
memcpy(indexPage+431, "#FFFF00", 6); // highlight (yellow) OFF
}
len = SPI_Ethernet_putConstString(httpHeader); // HTTP header
len += SPI_Ethernet_putConstString(httpMimeTypeHTML); // with HTML MIME type
len += SPI_Ethernet_putString(indexPage); // HTML page first part
return len; // return to the library with the number of bytes to transmit
}
unsigned int SPI_Ethernet_UserUDP(unsigned char *remoteHost, unsigned int remotePort,
unsigned int destPort, unsigned int reqLength, TEthPktFlags *flags)
{
return 0; // back to the library with the length of the UDP reply
}
unsigned long i, size, j, k;
char filename[14] = "ASHAN.TXT"; // File names
int txt2,*pi;
unsigned short character[20];
unsigned short *contentBuffer;
void main(){
ADCON1 |= 0x0D; // Configure AN0 and AN1 pins as analog
CMCON |= 7; // coparators off
TRISA = 0xff ;
PORTA = 0 ;
PORTB = 0 ; //PORTB output
TRISB = 0 ;
PORTC = 0 ;
TRISC = 0b11011100 ; // set PORTC as input except for bits 0 (RESET) and 1 (CS)
Delay_ms(100);
//Initialize LCD
Lcd_Init();
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF );
Lcd_Out(1, 1, "Status:");
Lcd_Cmd(_LCD_SECOND_ROW);
SPI1_Init();
SPI_Ethernet_Init(myMacAddr, myIpAddr,1);
SPI_Ethernet_initDHCP(5); // get network configuration from DHCP server, wait 5 sec for the response
memcpy(myIpAddr, Spi_Ethernet_getIpAddress(),4) ; // get assigned IP address
Lcd_Out_Cp(myIpAddr);
}
First think I'd do it's to run Wireshark and see if your DHCP discovery hits the wire or not, from that point you decide where the troubleshooting must be focused on...