On Tue, Mar 19, 2019 at 02:04:14PM +0200, Graham Leggett wrote: > > Why do you need to do the encode and decode? What's wrong with the original > > request object? > > The code is a modular ca, and different modules communicate with each other > generically using the standard DER encoded structures. Well, the *standard* structure for passing around just the unsigned data underlying a CSR (X509_REQ), is a CertificationRequestInfo (X509_REQ_INFO). So if the modules are to use *standard* structures to communicate. The object being passed needs to be either a CSR (signed) or the enclosed CRI (unsigned). You could, for example, sign the request with some suitable key (ideally the private key corresponding to the public key in the CSR, if available) before handing it off. If the signing key is not the enclosed public key, it would not pass "req -verify" (it never did before either, for lack of a signature), but the called module would be able to decode a CSR, and work as before. > > > While I can see a d2i_X509_REQ_INFO() function, I can’t find a > > > corresponding function in openssl 1.1.0+ that assigns this to a > > > X509_REQ, unless I am missing it? > > > > It should not be needed. > > I don’t follow - in order to get access to the data inside the X509_REQ_INFO > structure, I need to first wrap it in a X509_REQ, otherwise I have no API > calls to get access to the data inside it. No need to get access to the data inside an X509_REQ_INFO is expected. That object's sole purpose is to be serializable for signing. You have rather an edge-case, where for some reason you're delegating signing to a CA module by passing it a non-standard structure that *resembles* a CSR, which is however for some reason not signed with the subject key (not signed at all), and you expect the CA to apply policy, by decoding the CRI inside this non-CSR. OpenSSL 1.1.x does not have structure member accessors for a CRI, but they would be easy to add, that's essentially what the X509_REQ accessors do: long X509_REQ_get_version(const X509_REQ *req) { return ASN1_INTEGER_get(req->req_info.version); } X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req) { return req->req_info.subject; } int X509_REQ_get_attr_count(const X509_REQ *req) { return X509at_get_attr_count(req->req_info.attributes); } int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, int lastpos) { return X509at_get_attr_by_NID(req->req_info.attributes, nid, lastpos); } int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, const ASN1_OBJECT *obj, int lastpos) { return X509at_get_attr_by_OBJ(req->req_info.attributes, obj, lastpos); } X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc) { return X509at_get_attr(req->req_info.attributes, loc); } X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc) { return X509at_delete_attr(req->req_info.attributes, loc); } If one were to "void the warranty", one could cast the (X509_REQ_INFO *) as an (X509_REQ *), and the accessors would just work, but you must not do that, the internal details might change some day, as they did between 1.1.x and 1.0.2 (where the X509_REQ_INFO is a separately allocated structure pointed to by the X509_REQ). > > Can you be more specific about these "module boundaries”? > > The modules are Apache httpd modules, and the boundaries between the modules > are hooks that pass DER encoded structures between each module. Well, so the key question is, why not pass an actual CSR. What's preventing the CSR from being signed? > > This isn't pretty, and perhaps we need some new functions to explicitly > > embed a CRI in a CSR, but it is certainly something you can do in the > > short term. > > Can we not rather fix the initialisation of the X509_REQ in X509_REQ_new() > so that it works like it used to? It seems like a massive headache to do > something that used to be trivial. No, because it is not broken. The "massive headache" is peculiar to the rather odd choice of "RPC" between these Apache modules, where a non-CSR is masquerading as a CSR. > I see there have been changes to openssl code relating to how structures > are initialised, I suspect an error has crept in where an ASN.1 object is > missing instead of empty, thus the malformed CSR. There is no error. The X509_REQ_INFO and X509_ALGOR (signature algorithm) are now embedded in the CSR, and are no longer optional. Your immediate choices are to sign a CSR, or to embed your CRI in an outer DER wrapper that simulates a CSR. Signing with some key (ideally the subject key) seems simplest. Even if we provide the "missing" CRI accessors in OpenSSL 1.1.1c, I don't think that would practically solve your problem, because some users would have 1.1.0, 1.1.1, 1.1.1a or 1.1.1b. The DER wrapper is also simple (commented hex): $ openssl req -config <( printf "distinguished_name = dn\n[dn]\nprompt=yes\n[v3req]\n%s\n" \ "subjectAltName = DNS:example.com" ) \ -reqexts v3req -new -newkey rsa:1024 -keyout /dev/null \ -nodes -subj / 2>/dev/null | openssl req -outform DER | hexdump -ve '16/1 " %02x" "\n"' 30 82 01 68 30 81 d2 02 01 00 30 00 30 81 9f 30 # wrapper -->|<-- CRI DER begins here 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 d0 61 3e 71 9c f6 a1 d0 bd cf 7c f2 e6 be a2 5b 59 4a f5 8f 32 9d d6 47 38 43 1a 57 51 18 bd e1 a2 1d 52 d0 8d c5 79 07 c4 3c 78 19 5c ca c7 37 69 2a 22 70 05 e1 ab ec 35 b2 2b 1d 46 f7 8f b9 bd 30 27 08 81 1c ac 81 a1 c3 ed 5b 9f 9e 46 22 d3 28 45 3c 85 36 30 7e 11 46 ae 65 d0 8b 1d 19 28 3b 76 d6 f0 fd 59 b3 62 5a e9 45 21 92 29 1d 0f af ad 87 c9 33 fc 3d 87 5f 68 98 96 89 a6 b3 02 03 01 00 01 a0 29 30 27 06 09 2a 86 48 86 f7 0d 01 09 0e 31 1a 30 18 30 16 06 03 55 1d 11 04 0f 30 0d 82 0b 65 78 61 6d 70 6c 65 2e 63 6f 6d 30 0d 06 09 2a 86 48 # CRI DER ends here ------->|<--- begin sig OID 86 f7 0d 01 01 0b 05 00 03 81 81 00 00 00 00 00 # end sig OID ---->| null|<- 1024 zeroed sig bits 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # |<-- end sig Appending a fixed 147 byte suffix, and prepending an outer sequence tag and length is not difficult. But, since the signature is fake anyway, it could be much shorter, for example truncating it to an 8-bit "0" signature (19 byte suffix with the OID and null parameters), I get: $ perl -pe 's/\s//g; s/(..)/chr(hex($1))/eg;' <<-EOF | openssl req -inform DER -text 30 81 e8 30 81 d2 02 01 00 30 00 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 d0 61 3e 71 9c f6 a1 d0 bd cf 7c f2 e6 be a2 5b 59 4a f5 8f 32 9d d6 47 38 43 1a 57 51 18 bd e1 a2 1d 52 d0 8d c5 79 07 c4 3c 78 19 5c ca c7 37 69 2a 22 70 05 e1 ab ec 35 b2 2b 1d 46 f7 8f b9 bd 30 27 08 81 1c ac 81 a1 c3 ed 5b 9f 9e 46 22 d3 28 45 3c 85 36 30 7e 11 46 ae 65 d0 8b 1d 19 28 3b 76 d6 f0 fd 59 b3 62 5a e9 45 21 92 29 1d 0f af ad 87 c9 33 fc 3d 87 5f 68 98 96 89 a6 b3 02 03 01 00 01 a0 29 30 27 06 09 2a 86 48 86 f7 0d 01 09 0e 31 1a 30 18 30 16 06 03 55 1d 11 04 0f 30 0d 82 0b 65 78 61 6d 70 6c 65 2e 63 6f 6d 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 02 00 00 EOF Certificate Request: Data: Version: 0 (0x0) Subject: Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:d0:61:3e:71:9c:f6:a1:d0:bd:cf:7c:f2:e6:be: a2:5b:59:4a:f5:8f:32:9d:d6:47:38:43:1a:57:51: 18:bd:e1:a2:1d:52:d0:8d:c5:79:07:c4:3c:78:19: 5c:ca:c7:37:69:2a:22:70:05:e1:ab:ec:35:b2:2b: 1d:46:f7:8f:b9:bd:30:27:08:81:1c:ac:81:a1:c3: ed:5b:9f:9e:46:22:d3:28:45:3c:85:36:30:7e:11: 46:ae:65:d0:8b:1d:19:28:3b:76:d6:f0:fd:59:b3: 62:5a:e9:45:21:92:29:1d:0f:af:ad:87:c9:33:fc: 3d:87:5f:68:98:96:89:a6:b3 Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Alternative Name: DNS:example.com Signature Algorithm: sha256WithRSAEncryption 00 -----BEGIN CERTIFICATE REQUEST----- MIHoMIHSAgEAMAAwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANBhPnGc9qHQ vc988ua+oltZSvWPMp3WRzhDGldRGL3hoh1S0I3FeQfEPHgZXMrHN2kqInAF4avs NbIrHUb3j7m9MCcIgRysgaHD7VufnkYi0yhFPIU2MH4RRq5l0IsdGSg7dtbw/Vmz YlrpRSGSKR0Pr62HyTP8PYdfaJiWiaazAgMBAAGgKTAnBgkqhkiG9w0BCQ4xGjAY MBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAAwIAAA== -----END CERTIFICATE REQUEST----- The prefix would often be 4 bytes (i.e. 16-bit rather than an 8-bit length), rather than 3. As, for example always with 2048-bit RSA subject key. [ The above CSR is atypically short. ] -- Viktor.