Strip BOM on loading PEM files
authorDmitry Belyavskiy <beldmit@gmail.com>
Sun, 6 Oct 2019 19:25:10 +0000 (22:25 +0300)
committerViktor Dukhovni <openssl-users@dukhovni.org>
Fri, 25 Oct 2019 16:04:35 +0000 (18:04 +0200)
Reviewed-by: Richard Levitte <levitte@openssl.org>
Reviewed-by: Viktor Dukhovni <openssl-users@dukhovni.org>
crypto/pem/pem_lib.c
test/recipes/04-test_pem.t
test/recipes/04-test_pem_data/cert-bom.pem [new file with mode: 0644]

index eb07c88..020a030 100644 (file)
@@ -680,9 +680,20 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
 #endif
 
 /* Some helpers for PEM_read_bio_ex(). */
-static int sanitize_line(char *linebuf, int len, unsigned int flags)
+static int sanitize_line(char *linebuf, int len, unsigned int flags, int first_call)
 {
     int i;
+    if (first_call) {
+        /* Other BOMs imply unsupported multibyte encoding,
+         * so don't strip them and let the error raise */
+        const unsigned char utf8_bom[3] = {0xEF, 0xBB, 0xBF};
+
+        if (len > 3 && memcmp(linebuf, utf8_bom, 3) == 0) {
+            memmove(linebuf, linebuf + 3, len - 3);
+            linebuf[len - 3] = 0;
+            len -= 3;
+        }
+    }
 
     if (flags & PEM_FLAG_EAY_COMPATIBLE) {
         /* Strip trailing whitespace */
@@ -727,6 +738,7 @@ static int get_name(BIO *bp, char **name, unsigned int flags)
     char *linebuf;
     int ret = 0;
     int len;
+    int first_call = 1;
 
     /*
      * Need to hold trailing NUL (accounted for by BIO_gets() and the newline
@@ -747,7 +759,8 @@ static int get_name(BIO *bp, char **name, unsigned int flags)
         }
 
         /* Strip trailing garbage and standardize ending. */
-        len = sanitize_line(linebuf, len, flags & ~PEM_FLAG_ONLY_B64);
+        len = sanitize_line(linebuf, len, flags & ~PEM_FLAG_ONLY_B64, first_call);
+        first_call = 0;
 
         /* Allow leading empty or non-matching lines. */
     } while (strncmp(linebuf, beginstr, BEGINLEN) != 0
@@ -819,7 +832,7 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
         }
         if (!strncmp(linebuf, endstr, ENDLEN) || got_header == IN_HEADER)
             flags_mask &= ~PEM_FLAG_ONLY_B64;
-        len = sanitize_line(linebuf, len, flags & flags_mask);
+        len = sanitize_line(linebuf, len, flags & flags_mask, 0);
 
         /* Check for end of header. */
         if (linebuf[0] == '\n') {
index b8f4d72..0e6e419 100644 (file)
@@ -32,6 +32,7 @@ my %cert_expected = (
     "cert-256line.pem" => 1,
     "cert-257line.pem" => 1,
     "cert-blankline.pem" => 0,
+    "cert-bom.pem" => 1,
     "cert-comment.pem" => 0,
     "cert-earlypad.pem" => 0,
     "cert-extrapad.pem" => 0,
diff --git a/test/recipes/04-test_pem_data/cert-bom.pem b/test/recipes/04-test_pem_data/cert-bom.pem
new file mode 100644 (file)
index 0000000..91fbaf4
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEzDCCA7QCCQCgxkRox+YljjANBgkqhkiG9w0BAQsFADCCASYxYzBhBgNVBAgM
+WlRoZSBHcmVhdCBTdGF0ZSBvZiBMb25nLVdpbmRlZCBDZXJ0aWZpY2F0ZSBGaWVs
+ZCBOYW1lcyBXaGVyZWJ5IHRvIEluY3JlYXNlIHRoZSBPdXRwdXQgU2l6ZTEfMB0G
+A1UEBwwWVG9vbWFueWNoYXJhY3RlcnN2aWxsZTFIMEYGA1UECgw/VGhlIEJlbmV2
+b2xlbnQgU29jaWV0eSBvZiBMb3F1YWNpb3VzIGFuZCBQbGVvbmFzdGljIFBlcmlw
+aHJhc2lzMT0wOwYDVQQLDDRFbmRvcnNlbWVudCBvZiBWb3VjaHNhZmUnZCBFdmlk
+ZW50aWFyeSBDZXJ0aWZpY2F0aW9uMRUwEwYDVQQDDAxjZXJ0LmV4YW1wbGUwHhcN
+MTcwMjIzMjAyNTM2WhcNMTcwMzI1MjAyNTM2WjCCASYxYzBhBgNVBAgMWlRoZSBH
+cmVhdCBTdGF0ZSBvZiBMb25nLVdpbmRlZCBDZXJ0aWZpY2F0ZSBGaWVsZCBOYW1l
+cyBXaGVyZWJ5IHRvIEluY3JlYXNlIHRoZSBPdXRwdXQgU2l6ZTEfMB0GA1UEBwwW
+VG9vbWFueWNoYXJhY3RlcnN2aWxsZTFIMEYGA1UECgw/VGhlIEJlbmV2b2xlbnQg
+U29jaWV0eSBvZiBMb3F1YWNpb3VzIGFuZCBQbGVvbmFzdGljIFBlcmlwaHJhc2lz
+MT0wOwYDVQQLDDRFbmRvcnNlbWVudCBvZiBWb3VjaHNhZmUnZCBFdmlkZW50aWFy
+eSBDZXJ0aWZpY2F0aW9uMRUwEwYDVQQDDAxjZXJ0LmV4YW1wbGUwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7MOIrqH+ZIJiZdroKMrelKMSvvRKg2MEg
+j/sx9TaHHqrKys4AiL4Rq/ybQEigFC6G8mpZWbBrU+vN2SLr1ZsPftCHIY12LF56
+0WLYTYNqDgF5BdCZCrjJ2hhN+XwML2tgYdWioV/Eey8SJSqUskf03MpcwnLbVfSp
+hwmowqNfiEFFqPBCf7E8IVarGWctbMpvlMbAM5owhMev/Ccmqqt81NFkb1WVejvN
+5v/JKv243/Xedf4I7ZJv7zKeswoP9piFzWHXCd9SIVzWqF77u/crHufIhoEa7NkZ
+hSC2aosQF619iKnfk0nqWaLDJ182CCXkHERoQC7q9X2IGLDLoA0XAgMBAAEwDQYJ
+KoZIhvcNAQELBQADggEBAKbtLx+YlCGRCBmYn3dfYF+BIvK/b/e0DKNhDKhb4s9J
+ywlJ4qnAB48tgPx0q+ZB+EdMYRqCwyvXJxEdZ7PsCdUeU6xI2ybkhSdUUfQbYem3
+aYRG+yukGzazySQJs8lGqxBlRMFl/FGCg+oSQ/I32eGf8micDskj2zkAJtCkUPHX
+30YrWMfOwW1r2xYr2mBNXbNWXJhW/sIg5u8aa9fcALeuQcMXkbsbVoPmC5aLdiVZ
+rvUFoJ8DPg0aYYwj64RwU0B5HW/7jKhQ25FgKVAzLGrgYx1DivkM7UQGdWYnU8IA
+A8S89gRjGk2hnkeagWas3dxqTTpgJDhprgWzyKa9hII=
+-----END CERTIFICATE-----