+\ Get length of the list of anchor names to send to the client. The length
+\ includes the per-name 2-byte header, but _not_ the 2-byte header for
+\ the list itself. If no client certificate is requested, then this
+\ returns 0.
+cc: ta-names-total-length ( -- len ) {
+ size_t u, len;
+
+ len = 0;
+ if (CTX->ta_names != NULL) {
+ for (u = 0; u < CTX->num_tas; u ++) {
+ len += CTX->ta_names[u].len + 2;
+ }
+ } else if (CTX->tas != NULL) {
+ for (u = 0; u < CTX->num_tas; u ++) {
+ len += CTX->tas[u].dn.len + 2;
+ }
+ }
+ T0_PUSH(len);
+}
+
+\ Compute length and optionally write the contents of the list of
+\ supported client authentication methods.
+: write-list-auth ( do_write -- len )
+ 0
+ addr-cipher_suite get16 use-ecdh? if
+ 2+ over if 65 write8 66 write8 then
+ then
+ supports-rsa-sign? if 1+ over if 1 write8 then then
+ supports-ecdsa? if 1+ over if 64 write8 then then
+ swap drop ;
+
+: write-signhash-inner2 ( dow algo hashes len id -- dow algo hashes len )
+ { id }
+ over 1 id << and ifnot ret then
+ 2+
+ 3 pick if id write8 2 pick write8 then ;
+
+: write-signhash-inner1 ( dow algo hashes -- dow len )
+ 0
+ 4 write-signhash-inner2
+ 5 write-signhash-inner2
+ 6 write-signhash-inner2
+ 3 write-signhash-inner2
+ 2 write-signhash-inner2
+ -rot 2drop ;
+
+\ Compute length and optionally write the contents of the list of
+\ supported sign+hash algorithms.
+: write-list-signhash ( do_write -- len )
+ 0 { len }
+ \ If supporting neither RSA nor ECDSA in the engine, then we
+ \ will do only static ECDH, and thus we claim support for
+ \ everything (for the X.509 validator).
+ supports-rsa-sign? supports-ecdsa? or ifnot
+ 1 0x7C write-signhash-inner1 >len
+ 3 0x7C write-signhash-inner1 len +
+ swap drop ret
+ then
+ supports-rsa-sign? if
+ 1 supported-hash-functions drop
+ write-signhash-inner1 >len
+ then
+ supports-ecdsa? if
+ 3 supported-hash-functions drop
+ write-signhash-inner1 len + >len
+ then
+ drop len ;
+
+\ Initialise index for sending the list of anchor DN.
+cc: begin-ta-name-list ( -- ) {
+ CTX->cur_dn_index = 0;
+}
+
+\ Switch to next DN in the list. Returned value is the DN length, or -1
+\ if the end of the list was reached.
+cc: begin-ta-name ( -- len ) {
+ const br_x500_name *dn;
+ if (CTX->cur_dn_index >= CTX->num_tas) {
+ T0_PUSHi(-1);
+ } else {
+ if (CTX->ta_names == NULL) {
+ dn = &CTX->tas[CTX->cur_dn_index].dn;
+ } else {
+ dn = &CTX->ta_names[CTX->cur_dn_index];
+ }
+ CTX->cur_dn_index ++;
+ CTX->cur_dn = dn->data;
+ CTX->cur_dn_len = dn->len;
+ T0_PUSH(CTX->cur_dn_len);
+ }
+}
+
+\ Copy a chunk of the current DN into the pad. Returned value is the
+\ chunk length; this is 0 when the end of the current DN is reached.
+cc: copy-dn-chunk ( -- len ) {
+ size_t clen;
+
+ clen = CTX->cur_dn_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, CTX->cur_dn, clen);
+ CTX->cur_dn += clen;
+ CTX->cur_dn_len -= clen;
+ T0_PUSH(clen);
+}
+
+\ Write a CertificateRequest message.
+: write-CertificateRequest ( -- )
+ \ The list of client authentication types includes:
+ \ rsa_sign (1)
+ \ ecdsa_sign (64)
+ \ rsa_fixed_ecdh (65)
+ \ ecdsa_fixed_ecdh (66)
+ \ rsa_sign and ecdsa_sign require, respectively, RSA and ECDSA
+ \ support. Static ECDH requires that the cipher suite is ECDH.
+ \ When we ask for static ECDH, we always send both rsa_fixed_ecdh
+ \ and ecdsa_fixed_ecdh because what matters there is what the
+ \ X.509 engine may support, and we do not control that.
+ \
+ \ With TLS 1.2, we must also send a list of supported signature
+ \ and hash algorithms. That list is supposed to qualify both
+ \ the engine itself, and the X.509 validator, which are separate
+ \ in BearSSL. There again, we use the engine capabilities in that
+ \ list, and resort to a generic all-support list if only
+ \ static ECDH is accepted.
+ \
+ \ (In practice, client implementations tend to have at most one
+ \ or two certificates, and send the chain regardless of what
+ \ algorithms are used in it.)
+
+ 0 write-list-auth
+ addr-version get16 0x0303 >= if
+ 2+ 0 write-list-signhash +
+ then
+ ta-names-total-length + 3 +
+
+ \ Message header
+ 13 write8 write24
+
+ \ List of authentication methods
+ 0 write-list-auth write8 1 write-list-auth drop
+
+ \ For TLS 1.2+, list of sign+hash
+ addr-version get16 0x0303 >= if
+ 0 write-list-signhash write16 1 write-list-signhash drop
+ then
+
+ \ Trust anchor names
+ ta-names-total-length write16
+ begin-ta-name-list
+ begin
+ begin-ta-name
+ dup 0< if drop ret then write16
+ begin copy-dn-chunk dup while
+ addr-pad swap write-blob
+ repeat
+ drop
+ again ;
+