Skip to content

Commit b0ad6cb

Browse files
committed
Add relaxed certificate decoding
1 parent 329b224 commit b0ad6cb

10 files changed

Lines changed: 419 additions & 8 deletions

File tree

lib/public_key/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ src/OCSP-2024-08.erl
2727
src/OCSP-2024-08.hrl
2828
src/OTP-PKIX.erl
2929
src/OTP-PKIX.hrl
30+
src/OTP-PKIX-Relaxed.erl
31+
src/OTP-PKIX-Relaxed.hrl
3032
src/PKCS-1.erl
3133
src/PKCS-1.hrl
3234
src/PKCS-10.erl

lib/public_key/asn1/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ ASN_MODULES = \
6060
X509-ML-DSA-2025 \
6161
OCSP-2024-08 \
6262
OTP-PKIX \
63+
OTP-PKIX-Relaxed \
6364
PKCS-1 PKCS-3 PKCS-10 \
6465
PKIX-CommonTypes-2009 \
6566
PKIX-X400Address-2009 \
@@ -77,7 +78,7 @@ ASN_MODULES = \
7778
ASN_ASNS = $(ASN_MODULES:%=%.asn1)
7879
ASN_ERLS = $(ASN_TOP:%=$(ESRC)/%.erl)
7980
ASN_HRLS = PKCS-FRAME.hrl
80-
ASN_CONFIGS = OTP-PKIX.asn1config PKIX1Explicit-2009.asn1config
81+
ASN_CONFIGS = OTP-PKIX.asn1config OTP-PKIX-Relaxed.asn1config PKIX1Explicit-2009.asn1config
8182
ASN_DBS = $(ASN_MODULES:%=%.asn1db)
8283
ASN_TABLES = $(ASN_MODULES:%=%.table)
8384

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
-- %CopyrightBegin%
2+
--
3+
-- SPDX-License-Identifier: Apache-2.0
4+
--
5+
-- Copyright Ericsson AB 2008-2025. All Rights Reserved.
6+
--
7+
-- Licensed under the Apache License, Version 2.0 (the "License");
8+
-- you may not use this file except in compliance with the License.
9+
-- You may obtain a copy of the License at
10+
--
11+
-- http://www.apache.org/licenses/LICENSE-2.0
12+
--
13+
-- Unless required by applicable law or agreed to in writing, software
14+
-- distributed under the License is distributed on an "AS IS" BASIS,
15+
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
-- See the License for the specific language governing permissions and
17+
-- limitations under the License.
18+
--
19+
-- %CopyrightEnd%
20+
21+
OTP-PKIX-Relaxed {iso(1) identified-organization(3) dod(6) internet(1)
22+
private(4) enterprices(1) ericsson(193) otp(19) ssl(10)
23+
pkix1(1)}
24+
25+
DEFINITIONS EXPLICIT TAGS ::=
26+
27+
BEGIN
28+
29+
-- EXPORTS ALL
30+
31+
IMPORTS
32+
ATTRIBUTE, Extensions{}, SingleAttribute
33+
FROM PKIX-CommonTypes-2009
34+
35+
CertificateSerialNumber, CertExtensions{}, NoticeReference
36+
FROM PKIX1Implicit-2009
37+
{iso(1) identified-organization(3) dod(6) internet(1) security(5)
38+
mechanisms(5) pkix(7) id-mod(0) id-mod-pkix1-implicit-02(59)}
39+
40+
at-name, at-surname, at-givenName, at-initials, at-generationQualifier,
41+
at-x520CommonName, at-x520LocalityName, at-x520StateOrProvinceName,
42+
at-x520OrganizationName, at-x520OrganizationalUnitName, at-x520Title,
43+
at-x520dnQualifier, at-x520SerialNumber, at-x520Pseudonym,
44+
at-domainComponent, at-emailAddress,
45+
id-at-name, id-at-surname, id-at-givenName, id-at-initials, id-at-generationQualifier,
46+
id-at-commonName, id-at-localityName, id-at-stateOrProvinceName, id-at-organizationName,
47+
id-at-organizationalUnitName, id-at-title, id-at-countryName, id-at-serialNumber,
48+
id-at-pseudonym, id-emailAddress,
49+
ub-name, ub-common-name, ub-locality-name, ub-state-name, ub-organization-name,
50+
ub-organizational-unit-name, ub-title, ub-serial-number, ub-pseudonym, ub-emailaddress-length,
51+
Validity, Version, SubjectPublicKeyInfo,
52+
UniqueIdentifier,
53+
id-qt-unotice, id-qt-cps
54+
FROM PKIX1Explicit-2009
55+
{iso(1) identified-organization(3) dod(6) internet(1)
56+
security(5) mechanisms(5) pkix(7) id-mod(0)
57+
id-mod-pkix1-explicit-02(51)}
58+
59+
--Keys and Signatures
60+
dsa-with-sha1, DSA-Sig-Value, mda-sha1, pk-dsa, DSA-Params
61+
FROM PKIXAlgs-2009
62+
63+
AlgorithmIdentifier{}, SIGNATURE-ALGORITHM
64+
FROM AlgorithmInformation-2009
65+
{iso(1) identified-organization(3) dod(6) internet(1) security(5)
66+
mechanisms(5) pkix(7) id-mod(0)
67+
id-mod-algorithmInformation-02(58)};
68+
--
69+
-- Certificate
70+
--
71+
72+
OTPCertificate ::= SEQUENCE {
73+
tbsCertificate OTPTBSCertificate,
74+
signatureAlgorithm AlgorithmIdentifier{SIGNATURE-ALGORITHM,
75+
{ OTPSignatureAlgorithms }},
76+
signature BIT STRING }
77+
78+
OTPTBSCertificate ::= SEQUENCE {
79+
version [0] Version DEFAULT v1,
80+
serialNumber CertificateSerialNumber,
81+
signature AlgorithmIdentifier{SIGNATURE-ALGORITHM,
82+
{ OTPSignatureAlgorithms }},
83+
issuer OTPName,
84+
validity Validity,
85+
subject OTPName,
86+
subjectPublicKeyInfo SubjectPublicKeyInfo,
87+
... ,
88+
[[2: -- If present, version MUST be v2
89+
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
90+
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL
91+
]],
92+
[[3: -- If present, version MUST be v3 --
93+
extensions [3] Extensions{{CertExtensions}} OPTIONAL
94+
]], ... }
95+
96+
-- Here follows a workaround to handle very old certificates.
97+
98+
OTPSignatureAlgorithms SIGNATURE-ALGORITHM ::= {
99+
OTPSignatureAlgs, ...,
100+
PKIX1-PSS-OAEP-Algorithms-2009.SignatureAlgs }
101+
102+
OTPSignatureAlgs SIGNATURE-ALGORITHM ::= {
103+
PKIXAlgs-2009.sa-rsaWithMD2 |
104+
PKIXAlgs-2009.sa-rsaWithMD5 |
105+
PKIXAlgs-2009.sa-rsaWithSHA1 |
106+
otp-sa-dsaWithSHA1 |
107+
PKIXAlgs-2009.sa-ecdsaWithSHA1,
108+
..., -- Extensible
109+
PKIXAlgs-2009.sa-dsaWithSHA224 |
110+
PKIXAlgs-2009.sa-dsaWithSHA256 |
111+
PKIXAlgs-2009.sa-ecdsaWithSHA224 |
112+
PKIXAlgs-2009.sa-ecdsaWithSHA256 |
113+
PKIXAlgs-2009.sa-ecdsaWithSHA384 |
114+
PKIXAlgs-2009.sa-ecdsaWithSHA512
115+
}
116+
117+
otp-sa-dsaWithSHA1 SIGNATURE-ALGORITHM ::= {
118+
IDENTIFIER dsa-with-sha1
119+
VALUE DSA-Sig-Value
120+
-- Allow DSA-Params as well as NULL here.
121+
PARAMS TYPE OTP-DSA-Params-Or-NULL ARE absent
122+
HASHES { mda-sha1 }
123+
PUBLIC-KEYS { pk-dsa }
124+
SMIME-CAPS { IDENTIFIED BY dsa-with-sha1 }
125+
}
126+
127+
OTP-DSA-Params-Or-NULL ::= CHOICE {
128+
present DSA-Params, -- Only in very old certificates.
129+
absent NULL
130+
}
131+
132+
-- OTPName can contain country name and email addresses that don't
133+
-- follow the standard.
134+
135+
OTPName ::= CHOICE {
136+
rdnSequence RDNSequence }
137+
138+
RDNSequence ::= SEQUENCE OF OTPRelativeDistinguishedName
139+
140+
OTPRelativeDistinguishedName ::=
141+
SET SIZE (1 .. MAX) OF SingleAttribute { {OTPSupportedAttributes} }
142+
143+
OTPSupportedAttributes ATTRIBUTE ::= {
144+
otp-at-name | otp-at-surname | otp-at-givenName | otp-at-initials |
145+
otp-at-generationQualifier | otp-at-x520CommonName |
146+
otp-at-x520LocalityName | otp-at-x520StateOrProvinceName |
147+
otp-at-x520OrganizationName | otp-at-x520OrganizationalUnitName |
148+
otp-at-x520Title | at-x520dnQualifier | otp-at-x520countryName |
149+
otp-at-x520SerialNumber | otp-at-x520Pseudonym | at-domainComponent |
150+
otp-at-emailAddress, ... }
151+
152+
OTPDirectoryString{INTEGER:maxSize} ::= CHOICE {
153+
teletexString TeletexString(SIZE (0..maxSize)),
154+
printableString PrintableString(SIZE (0..maxSize)),
155+
bmpString BMPString(SIZE (0..maxSize)),
156+
universalString UniversalString(SIZE (0..maxSize)),
157+
-- Note: The tag was spelled as `uTF8String` in the
158+
-- RFC for unknown reason. That breaks backward
159+
-- for public_key.
160+
utf8String UTF8String(SIZE (0..maxSize))
161+
}
162+
163+
OTP-X520name ::= OTPDirectoryString { ub-name }
164+
165+
otp-at-name ATTRIBUTE ::= {
166+
TYPE OTP-X520name IDENTIFIED BY id-at-name }
167+
168+
otp-at-surname ATTRIBUTE ::= {
169+
TYPE OTP-X520name IDENTIFIED BY id-at-surname }
170+
171+
otp-at-givenName ATTRIBUTE ::= {
172+
TYPE OTP-X520name IDENTIFIED BY id-at-givenName }
173+
174+
otp-at-initials ATTRIBUTE ::= {
175+
TYPE OTP-X520name IDENTIFIED BY id-at-initials }
176+
177+
otp-at-generationQualifier ATTRIBUTE ::= {
178+
TYPE OTP-X520name IDENTIFIED BY id-at-generationQualifier }
179+
180+
otp-at-x520LocalityName ATTRIBUTE ::= {
181+
TYPE OTP-X520localityName IDENTIFIED BY id-at-localityName }
182+
OTP-X520localityName ::= OTPDirectoryString { ub-locality-name }
183+
184+
otp-at-x520StateOrProvinceName ATTRIBUTE ::= {
185+
TYPE OTP-X520stateOrProvinceName IDENTIFIED BY id-at-stateOrProvinceName }
186+
OTP-X520stateOrProvinceName ::= OTPDirectoryString { ub-state-name }
187+
188+
otp-at-x520CommonName ATTRIBUTE ::= {
189+
TYPE OTP-X520commonName IDENTIFIED BY id-at-commonName }
190+
OTP-X520commonName ::= OTPDirectoryString { ub-common-name }
191+
192+
otp-at-x520OrganizationName ATTRIBUTE ::= {
193+
TYPE OTP-X520organizationName IDENTIFIED BY id-at-organizationName }
194+
OTP-X520organizationName ::= OTPDirectoryString { ub-organization-name }
195+
196+
otp-at-x520OrganizationalUnitName ATTRIBUTE ::= {
197+
TYPE OTP-X520organizationalUnitName IDENTIFIED BY id-at-organizationalUnitName }
198+
OTP-X520organizationalUnitName ::= OTPDirectoryString { ub-organizational-unit-name }
199+
200+
otp-at-x520Title ATTRIBUTE ::= {
201+
TYPE OTP-X520title IDENTIFIED BY id-at-title }
202+
OTP-X520title ::= OTPDirectoryString { ub-title }
203+
204+
otp-at-x520countryName ATTRIBUTE ::= {
205+
TYPE OTP-X520countryName IDENTIFIED BY id-at-countryName }
206+
-- We accept utf8String encoding of the US-ASCII
207+
-- country name code and the mix up with other country code systems
208+
-- that uses three characters instead of two.
209+
OTP-X520countryName ::= CHOICE {
210+
correct PrintableString (SIZE(0) | SIZE (2..3)), -- Correct size is 2.
211+
wrong UTF8String (SIZE(0) | SIZE (2..3))
212+
}
213+
214+
otp-at-x520SerialNumber ATTRIBUTE ::= {
215+
TYPE OTP-X520serialNumber IDENTIFIED BY id-at-serialNumber }
216+
OTP-X520serialNumber ::= OTPDirectoryString { ub-serial-number }
217+
218+
otp-at-x520Pseudonym ATTRIBUTE ::= {
219+
TYPE OTP-X520pseudonym IDENTIFIED BY id-at-pseudonym }
220+
OTP-X520pseudonym ::= OTPDirectoryString { ub-pseudonym }
221+
222+
otp-at-emailAddress ATTRIBUTE ::= {
223+
TYPE OTP-emailAddress IDENTIFIED BY id-emailAddress }
224+
OTP-emailAddress ::= CHOICE {
225+
correct IA5String (SIZE (0..ub-emailaddress-length)),
226+
wrong UTF8String
227+
}
228+
229+
-- We use this variation of SingleAttribute/AttributeTypeAndValue
230+
-- when calculating the "short" hash of the certificate issuer.
231+
-- See public_key:short_name_hash/1.
232+
233+
HashSingleAttribute ::= SEQUENCE {
234+
type OBJECT IDENTIFIER,
235+
value UTF8String
236+
}
237+
238+
HashRDNSequence ::= SEQUENCE OF HashRelativeDistinguishedName
239+
240+
HashRelativeDistinguishedName ::=
241+
SET SIZE (1 .. MAX) OF HashSingleAttribute
242+
243+
-- Used to workaround that some CAs create too long User Notices
244+
245+
OTPCertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF OTPPolicyInformation
246+
247+
OTPPolicyInformation ::= SEQUENCE {
248+
policyIdentifier CertPolicyId,
249+
policyQualifiers SEQUENCE SIZE (1..MAX) OF
250+
OTPPolicyQualifierInfo OPTIONAL }
251+
252+
CertPolicyId ::= OBJECT IDENTIFIER
253+
254+
CERT-POLICY-QUALIFIER ::= TYPE-IDENTIFIER
255+
256+
OTPPolicyQualifierInfo ::= SEQUENCE {
257+
policyQualifierId CERT-POLICY-QUALIFIER.
258+
&id({PolicyQualifierId}),
259+
qualifier CERT-POLICY-QUALIFIER.
260+
&Type({PolicyQualifierId}{@policyQualifierId})}
261+
262+
-- Implementations that recognize additional policy qualifiers MUST
263+
-- augment the following definition for PolicyQualifierId
264+
265+
PolicyQualifierId CERT-POLICY-QUALIFIER ::=
266+
{ pqid-cps | pqid-unotice, ... }
267+
268+
pqid-cps CERT-POLICY-QUALIFIER ::= { CPSuri IDENTIFIED BY id-qt-cps }
269+
pqid-unotice CERT-POLICY-QUALIFIER ::= { OTPUserNotice
270+
IDENTIFIED BY id-qt-unotice }
271+
272+
-- CPS pointer qualifier
273+
274+
CPSuri ::= IA5String
275+
276+
OTPUserNotice ::= SEQUENCE {
277+
noticeRef NoticeReference OPTIONAL,
278+
explicitText OTPDisplayText OPTIONAL}
279+
280+
-- NoticeReference ::= SEQUENCE {
281+
-- organization OTPDisplayText,
282+
-- noticeNumbers SEQUENCE OF INTEGER }
283+
284+
OTPDisplayText ::= CHOICE {
285+
ia5String IA5String (SIZE (1..650)),
286+
visibleString VisibleString (SIZE (1..650)),
287+
bmpString BMPString (SIZE (1..650)),
288+
utf8String UTF8String (SIZE (1..650)) }
289+
290+
-- Extensions
291+
292+
Extensions ::= SEQUENCE SIZE (1..MAX) OF OTPExtension
293+
294+
OTPExtension ::= SEQUENCE {
295+
extnID OBJECT IDENTIFIER,
296+
critical BOOLEAN DEFAULT FALSE,
297+
extnValue OCTET STRING }
298+
299+
END
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
%% -*- erlang -*-
2+
%%
3+
%% %CopyrightBegin%
4+
%%
5+
%% SPDX-License-Identifier: Apache-2.0
6+
%%
7+
%% Copyright Ericsson AB 2008-2025. All Rights Reserved.
8+
%%
9+
%% Licensed under the Apache License, Version 2.0 (the "License");
10+
%% you may not use this file except in compliance with the License.
11+
%% You may obtain a copy of the License at
12+
%%
13+
%% http://www.apache.org/licenses/LICENSE-2.0
14+
%%
15+
%% Unless required by applicable law or agreed to in writing, software
16+
%% distributed under the License is distributed on an "AS IS" BASIS,
17+
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
%% See the License for the specific language governing permissions and
19+
%% limitations under the License.
20+
%%
21+
%% %CopyrightEnd%
22+
23+
{exclusive_decode,
24+
{'OTP-PKIX-Relaxed',
25+
[{decode_TBSCert_exclusive,['OTPCertificate',[{tbsCertificate,undecoded}]]}]}}.

lib/public_key/src/pubkey_cert.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ validate_signature(Cert, DerCert, Key, KeyParams0,
280280
%% Description: Extracts data from DerCert needed to call public_key:verify/4.
281281
%%--------------------------------------------------------------------
282282
verify_data(DerCert) ->
283-
{ok, OtpCert} = pubkey_cert_records:decode_cert(DerCert),
283+
{ok, OtpCert} = pubkey_cert_records:decode_cert(DerCert, relaxed),
284284
extract_verify_data(OtpCert, DerCert).
285285

286286
%%--------------------------------------------------------------------

0 commit comments

Comments
 (0)