|
1 | 1 | /* |
2 | | - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
28 | 28 | import java.io.ByteArrayOutputStream; |
29 | 29 | import java.io.IOException; |
30 | 30 | import java.io.Reader; |
| 31 | +import java.nio.charset.Charset; |
31 | 32 | import java.text.Normalizer; |
32 | 33 | import java.util.*; |
33 | 34 |
|
| 35 | +import static java.nio.charset.StandardCharsets.ISO_8859_1; |
34 | 36 | import static java.nio.charset.StandardCharsets.UTF_8; |
| 37 | +import static java.nio.charset.StandardCharsets.UTF_16BE; |
35 | 38 |
|
36 | 39 | import sun.security.action.GetBooleanAction; |
37 | 40 | import sun.security.util.*; |
@@ -594,6 +597,10 @@ private static boolean trailingSpace(Reader in) throws IOException { |
594 | 597 | throw new IOException("AVA, extra bytes = " |
595 | 598 | + derval.data.available()); |
596 | 599 | } |
| 600 | + |
| 601 | + if (value.tag == DerValue.tag_BMPString) { |
| 602 | + value.validateBMPString(); |
| 603 | + } |
597 | 604 | } |
598 | 605 |
|
599 | 606 | AVA(DerInputStream in) throws IOException { |
@@ -735,7 +742,7 @@ public String toRFC2253String(Map<String, String> oidMap) { |
735 | 742 | */ |
736 | 743 | String valStr = null; |
737 | 744 | try { |
738 | | - valStr = new String(value.getDataBytes(), UTF_8); |
| 745 | + valStr = new String(value.getDataBytes(), getCharset(value, false)); |
739 | 746 | } catch (IOException ie) { |
740 | 747 | throw new IllegalArgumentException("DER Value conversion"); |
741 | 748 | } |
@@ -870,7 +877,7 @@ public String toRFC2253CanonicalString() { |
870 | 877 | */ |
871 | 878 | String valStr = null; |
872 | 879 | try { |
873 | | - valStr = new String(value.getDataBytes(), UTF_8); |
| 880 | + valStr = new String(value.getDataBytes(), getCharset(value, true)); |
874 | 881 | } catch (IOException ie) { |
875 | 882 | throw new IllegalArgumentException("DER Value conversion"); |
876 | 883 | } |
@@ -977,6 +984,39 @@ private static boolean isDerString(DerValue value, boolean canonical) { |
977 | 984 | } |
978 | 985 | } |
979 | 986 |
|
| 987 | + /* |
| 988 | + * Returns the charset that should be used to decode each DN string type. |
| 989 | + * |
| 990 | + * This method ensures that multi-byte (UTF8String and BMPString) types |
| 991 | + * are decoded using the correct charset and the String forms represent |
| 992 | + * the correct characters. For 8-bit ASCII-based types (PrintableString |
| 993 | + * and IA5String), we return ISO_8859_1 rather than ASCII, so that the |
| 994 | + * complete range of characters can be represented, as many certificates |
| 995 | + * do not comply with the Internationalized Domain Name ACE format. |
| 996 | + * |
| 997 | + * NOTE: this method only supports DirectoryStrings of the types returned |
| 998 | + * by isDerString(). |
| 999 | + */ |
| 1000 | + private static Charset getCharset(DerValue value, boolean canonical) { |
| 1001 | + if (canonical) { |
| 1002 | + return switch (value.tag) { |
| 1003 | + case DerValue.tag_PrintableString -> ISO_8859_1; |
| 1004 | + case DerValue.tag_UTF8String -> UTF_8; |
| 1005 | + default -> throw new Error("unexpected tag: " + value.tag); |
| 1006 | + }; |
| 1007 | + } |
| 1008 | + |
| 1009 | + return switch (value.tag) { |
| 1010 | + case DerValue.tag_PrintableString, |
| 1011 | + DerValue.tag_T61String, |
| 1012 | + DerValue.tag_IA5String, |
| 1013 | + DerValue.tag_GeneralString -> ISO_8859_1; |
| 1014 | + case DerValue.tag_BMPString -> UTF_16BE; |
| 1015 | + case DerValue.tag_UTF8String -> UTF_8; |
| 1016 | + default -> throw new Error("unexpected tag: " + value.tag); |
| 1017 | + }; |
| 1018 | + } |
| 1019 | + |
980 | 1020 | boolean hasRFC2253Keyword() { |
981 | 1021 | return AVAKeyword.hasKeyword(oid, RFC2253); |
982 | 1022 | } |
|
0 commit comments