I am trying to generate a CSR (Certificate Signing Request) in an embedded device. I have implemented some OpenSSL functions in one embedded device. Unfortunately I only have a few functions available. So far I've been able to generate an RSA private key and now I need to generate the CSR.
My library does NOT have any of the functions such as X509_REQ_new()
, X509_REQ_get_subject_name()
etc. Therefore I'm building the CSR by means of creating a DER file directly.
The CSR in DER format is decoded as follows:
- ASN1 Sequence
- Version
- Subject(s) name(s)
- Type of encryption
- Modulus & Exponent (from my RSA Key)
- Attributes
- Signature (here is where my problem lies)
If I had all the OpenSSL functions available I would use X509_REQ_sign(x509_req, pKey, EVP_sha1())
, but as I said before I don't have any of the X509 objects available.
What do I need to sign in order to build that part?
By 'implemented' do you mean you coded them yourself, or you selected chunks out of the OpenSSL source? In the latter case I assume you have the full source available to look at even if it isn't compiled on your limited device.
CSRs, like (X.509) certs and CRLs, use a common top-level structure:
Note that AlgId and signature are separate items and outside the SEQUENCE in the body, though inside the top-level SEQUENCE.
For CSR this is laid out in PKCS#10, more stably available as RFC2986; see section 4.
In particular I hope your "4.- Type of encryption" is really an AlgorithmIdentifier for the algorithm of the publickey which for RSA for historical reasons is the OID
rsaEncryption = 1.2.840.113549.1.1.1
even though RSA is used for signature as well as encryption and "5.- Modulus & Exponent" is really a BIT STRING containing the DER encoding of a PKCS#1 public key which is a SEQUENCE containing those two INTEGERs, and that 4 and 5 are grouped into a SEQUENCE to form SubjectPublicKeyInfo.As described in section 4.2, the 'body' part (certificationRequestInfo) is DER-encoded, and that encoding is signed by your privatekey -- for RSA in practice using PKCS1-v1_5, although there are other RSA signature schemes defined. That signature scheme produces an octet string (in the generic sense, not the ASN.1 type) which is used as the value in the BIT STRING.
Depending on what primitives you are using, remember that PKCS1-v1_5 requires you to hash the message (here certificationRequestInfo), encode that hash in an ASN.1 SEQUENCE with an AlgId for the hash, pad that ASN.1 with 01 FF... 00, and modexp (OS2I of) the result with d. In OpenSSL
EVP_DigestSign*
does all 4 steps,EVP_PKEY_sign*
does the last 3, andRSA_private_encrypt
[sic] does the last 2 i.e. does NOT do the ASN.1 (and optionally doesn't do the padding either).Your comments are too vague for me to be clear what you are doing, so here is a VALID EXAMPLE:
This consists of the outer SEQUENCE tag & length, then the TBS or body (certificationRequestInfo) at 4 up to 0x16E which is this DER encoding:
followed by the AlgId for the signature (aka the 'outer' AlgId) at 0x16E up to 0x17D:
followed by a BIT STRING containing the signature value from 0x182 up to 0x282. This can be verified as the signature of the TBS:
or since PKCS1-v1_5 signature is deterministic we can recreate the same signature:
Finally, since this (like most) RSA signature allows 'recovery' (sometimes misleadingly called 'decrypt with public key') we can look at the value actually input to the modexp-d:
and see this consists of type-01 padding of an ASN.1 SEQUENCE containing an AlgId for SHA1 plus an OCTET STRING containing the actual hash: