@@ -587,37 +587,125 @@ nc_tls_cert_dup(const mbedtls_x509_crt *cert)
587587}
588588
589589/**
590- * @brief Duplicate a certificate and append it to a chain.
590+ * @brief Duplicate a certificate and prepend it to a chain.
591591 *
592- * @param[in] cert Certificate to duplicate and append .
593- * @param[in,out] chain Chain to append the certificate to.
592+ * @param[in] cert Certificate to duplicate and prepend .
593+ * @param[in,out] chain Chain to prepend the certificate to.
594594 * @return 0 on success, -1 on error.
595595 */
596596static int
597- nc_server_tls_append_cert_to_chain (mbedtls_x509_crt * cert , mbedtls_x509_crt * * chain )
597+ nc_server_tls_prepend_cert_to_chain (mbedtls_x509_crt * cert , mbedtls_x509_crt * * chain )
598598{
599- mbedtls_x509_crt * iter , * copy ;
599+ mbedtls_x509_crt * copy ;
600600
601601 copy = nc_tls_cert_dup (cert );
602602 if (!copy ) {
603603 return -1 ;
604604 }
605605
606- if (!* chain ) {
607- /* first in the list */
608- * chain = copy ;
609- } else {
610- /* find the last cert */
611- iter = * chain ;
612- while (iter -> next ) {
613- iter = iter -> next ;
606+ copy -> next = * chain ;
607+ * chain = copy ;
608+
609+ return 0 ;
610+ }
611+
612+ /**
613+ * @brief Check whether a certificate is already present in a chain.
614+ *
615+ * @param[in] cert Certificate to search for.
616+ * @param[in] chain Certificate chain.
617+ * @return 1 if found, 0 otherwise.
618+ */
619+ static int
620+ nc_server_tls_cert_in_chain (const mbedtls_x509_crt * cert , const mbedtls_x509_crt * chain )
621+ {
622+ const mbedtls_x509_crt * iter ;
623+
624+ for (iter = chain ; iter ; iter = iter -> next ) {
625+ if (cert -> raw .p && iter -> raw .p && (cert -> raw .len == iter -> raw .len ) && !memcmp (cert -> raw .p , iter -> raw .p , cert -> raw .len )) {
626+ return 1 ;
614627 }
615- iter -> next = copy ;
616628 }
617629
618630 return 0 ;
619631}
620632
633+ /**
634+ * @brief Prepend issuer chain for a certificate.
635+ *
636+ * Repeatedly parse issuer_raw of @p cert into a certificate, then parse issuer_raw
637+ * of that parsed issuer, and so on. Parsed issuers are prepended into @p chain in
638+ * root-first order so that prepending the actual cert afterwards yields peer-first
639+ * order.
640+ *
641+ * @param[in] cert Certificate whose issuers are to be prepended.
642+ * @param[in,out] chain Chain to prepend issuer certificates to.
643+ * @return 0 on success, -1 on error.
644+ */
645+ static int
646+ nc_server_tls_prepend_issuer_chain (mbedtls_x509_crt * cert , mbedtls_x509_crt * * chain )
647+ {
648+ size_t i = 0 ;
649+ mbedtls_x509_crt * copy ;
650+ const mbedtls_x509_crt * issuer , * iter , * cur ;
651+ mbedtls_x509_crt * issuers [MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE - 1 ];
652+
653+ cur = cert ;
654+ while (cur && (i < (sizeof issuers / sizeof * issuers ))) {
655+ if (!cur -> issuer_raw .p || !cur -> issuer_raw .len ) {
656+ break ;
657+ }
658+
659+ if ((cur -> issuer_raw .len == cur -> subject_raw .len ) && !memcmp (cur -> issuer_raw .p , cur -> subject_raw .p , cur -> issuer_raw .len )) {
660+ /* self-issued root reached */
661+ break ;
662+ }
663+
664+ /* find issuer cert by matching issuer DN to subject DN */
665+ issuer = NULL ;
666+ for (iter = cert ; iter ; iter = iter -> next ) {
667+ if ((iter -> subject_raw .len == cur -> issuer_raw .len ) &&
668+ !memcmp (iter -> subject_raw .p , cur -> issuer_raw .p , cur -> issuer_raw .len )) {
669+ issuer = iter ;
670+ break ;
671+ }
672+ }
673+ if (!issuer ) {
674+ /* no more issuers available in the certificate set */
675+ break ;
676+ }
677+
678+ if (nc_server_tls_cert_in_chain (issuer , * chain )) {
679+ /* already present in chain */
680+ break ;
681+ }
682+
683+ copy = nc_tls_cert_dup (issuer );
684+ if (!copy ) {
685+ goto error ;
686+ }
687+
688+ issuers [i ] = copy ;
689+ ++ i ;
690+ cur = issuer ;
691+ }
692+
693+ while (i ) {
694+ -- i ;
695+ issuers [i ]-> next = * chain ;
696+ * chain = issuers [i ];
697+ }
698+
699+ return 0 ;
700+
701+ error :
702+ while (i ) {
703+ -- i ;
704+ nc_tls_cert_destroy_wrap (issuers [i ]);
705+ }
706+ return -1 ;
707+ }
708+
621709/**
622710 * @brief Verify a certificate.
623711 *
@@ -634,11 +722,22 @@ nc_server_tls_verify_cb(void *cb_data, mbedtls_x509_crt *cert, int depth, uint32
634722 struct nc_tls_verify_cb_data * data = cb_data ;
635723 char * err ;
636724
637- /* append to the chain we're building */
638- ret = nc_server_tls_append_cert_to_chain (cert , (mbedtls_x509_crt * * )& data -> chain );
639- if (ret ) {
640- nc_tls_cert_destroy_wrap (data -> chain );
641- return MBEDTLS_ERR_X509_ALLOC_FAILED ;
725+ if (!data -> chain ) {
726+ /* first call, prepend the issuer chain so that we have the whole chain available for CTN */
727+ ret = nc_server_tls_prepend_issuer_chain (cert , (mbedtls_x509_crt * * )& data -> chain );
728+ if (ret ) {
729+ nc_tls_cert_destroy_wrap (data -> chain );
730+ return MBEDTLS_ERR_X509_ALLOC_FAILED ;
731+ }
732+ }
733+
734+ /* prepend to the chain we're building to maintain peer-first order */
735+ if (!nc_server_tls_cert_in_chain (cert , (const mbedtls_x509_crt * )data -> chain )) {
736+ ret = nc_server_tls_prepend_cert_to_chain (cert , (mbedtls_x509_crt * * )& data -> chain );
737+ if (ret ) {
738+ nc_tls_cert_destroy_wrap (data -> chain );
739+ return MBEDTLS_ERR_X509_ALLOC_FAILED ;
740+ }
642741 }
643742
644743 if (!* flags ) {
@@ -836,18 +935,22 @@ nc_tls_get_num_certs_wrap(void *chain)
836935 return n ;
837936}
838937
839- void
840- nc_tls_get_cert_wrap (void * chain , int idx , void * * cert )
938+ void *
939+ nc_tls_get_cert_wrap (void * chain , int idx )
841940{
842941 int i ;
843942 mbedtls_x509_crt * iter ;
844943
944+ if (!chain || (idx < 0 )) {
945+ return NULL ;
946+ }
947+
845948 iter = chain ;
846- for (i = 0 ; i < idx ; i ++ ) {
949+ for (i = 0 ; iter && ( i < idx ) ; i ++ ) {
847950 iter = iter -> next ;
848951 }
849952
850- * cert = iter ;
953+ return iter ;
851954}
852955
853956int
0 commit comments