Fix reading broken BER in gcrypt/rsa.c
authorKirill Isakov <bootctl@gmail.com>
Wed, 27 Apr 2022 09:49:32 +0000 (15:49 +0600)
committerKirill Isakov <bootctl@gmail.com>
Wed, 27 Apr 2022 14:45:48 +0000 (20:45 +0600)
Our hand-rolled BER parser was reading ASN.1 sequence length without
checking if there's a sequence tag (0x10) before it.

src/gcrypt/asn1.h [new file with mode: 0644]
src/gcrypt/rsa.c
src/gcrypt/rsagen.c

diff --git a/src/gcrypt/asn1.h b/src/gcrypt/asn1.h
new file mode 100644 (file)
index 0000000..6709fa3
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef TINC_GCRYPT_ASN1_H
+#define TINC_GCRYPT_ASN1_H
+
+// https://luca.ntop.org/Teaching/Appunti/asn1.html
+typedef enum {
+       TAG_INTEGER = 2,
+       TAG_SEQUENCE = 16,
+} asn1_tag_t;
+
+#endif // TINC_GCRYPT_ASN1_H
index 83f177b..04aa358 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "pem.h"
 
+#include "asn1.h"
 #include "rsa.h"
 #include "../logger.h"
 #include "../rsa.h"
@@ -84,20 +85,11 @@ static size_t ber_read_len(unsigned char **p, size_t *buflen) {
        }
 }
 
-
-static bool ber_read_sequence(unsigned char **p, size_t *buflen, size_t *result) {
+static bool ber_skip_sequence(unsigned char **p, size_t *buflen) {
        int tag = ber_read_id(p, buflen);
-       size_t len = ber_read_len(p, buflen);
-
-       if(tag == 0x10) {
-               if(result) {
-                       *result = len;
-               }
 
-               return true;
-       } else {
-               return false;
-       }
+       return tag == TAG_SEQUENCE &&
+              ber_read_len(p, buflen) > 0;
 }
 
 static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
@@ -172,7 +164,7 @@ rsa_t *rsa_read_pem_public_key(FILE *fp) {
 
        rsa_t *rsa = xzalloc(sizeof(rsa_t));
 
-       if(!ber_read_sequence(&derp, &derlen, NULL)
+       if(!ber_skip_sequence(&derp, &derlen)
                        || !ber_read_mpi(&derp, &derlen, &rsa->n)
                        || !ber_read_mpi(&derp, &derlen, &rsa->e)
                        || derlen) {
@@ -195,7 +187,7 @@ rsa_t *rsa_read_pem_private_key(FILE *fp) {
 
        rsa_t *rsa = xzalloc(sizeof(rsa_t));
 
-       if(!ber_read_sequence(&derp, &derlen, NULL)
+       if(!ber_skip_sequence(&derp, &derlen)
                        || !ber_read_mpi(&derp, &derlen, NULL)
                        || !ber_read_mpi(&derp, &derlen, &rsa->n)
                        || !ber_read_mpi(&derp, &derlen, &rsa->e)
index 8576555..b89225d 100644 (file)
 #include <gcrypt.h>
 #include <assert.h>
 
+#include "asn1.h"
 #include "rsa.h"
 #include "pem.h"
 #include "../rsagen.h"
 #include "../xalloc.h"
 #include "../utils.h"
 
-// ASN.1 tags.
-typedef enum {
-       TAG_INTEGER = 2,
-       TAG_SEQUENCE = 16,
-} asn1_tag_t;
-
 static size_t der_tag_len(size_t n) {
        if(n < 128) {
                return 2;