Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions v3/lints/etsi/lint_qcstatem_psd2_ncaname_valid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* ZLint Copyright 2026 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package etsi

import (
"unicode/utf8"

"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/util"
)

type qcStatemPsd2NcaNameValid struct{}

// ETSI TS 119 495 V1.8.1 (2026-04), Section 5.2.3:
//
// GEN-5.2.3-1: The NCAName shall be plain text using Latin alphabet
// provided by the Competent Authority itself for purpose of
// identification in certificates.
//
// NCAName ::= UTF8String (SIZE(1..256))
//
// GEN-5.2.3-1A: If the subject role is international central bank
// (PSP_CB) or international public authority (PSP_PA), NCAName shall
// have the value "NA".
func init() {
lint.RegisterCertificateLint(&lint.CertificateLint{
LintMetadata: lint.LintMetadata{
Name: "e_qcstatem_psd2_ncaname_valid",
Description: "Checks that the NCAName field of a PSD2 QcStatement is non-empty and at most 256 characters, or 'NA' for a certificate declaring a PSP_CB or PSP_PA role",
Citation: "ETSI TS 119 495 V1.8.1 (2026-04), Section 5.2.3, GEN-5.2.3-1, GEN-5.2.3-1A",
Source: lint.EtsiEsi,
EffectiveDate: util.EtsiTs119495_V1_1_2_Date,
},
Lint: NewQcStatemPsd2NcaNameValid,
})
}

func NewQcStatemPsd2NcaNameValid() lint.LintInterface {
return &qcStatemPsd2NcaNameValid{}
}

func (l *qcStatemPsd2NcaNameValid) CheckApplies(c *x509.Certificate) bool {
if !util.IsExtInCert(c, util.QcStateOid) {
return false
}
return util.ParseQcStatem(util.GetExtFromCert(c, util.QcStateOid).Value, util.IdEtsiPsd2Statem).IsPresent()
}

func (l *qcStatemPsd2NcaNameValid) Execute(c *x509.Certificate) *lint.LintResult {
ext := util.GetExtFromCert(c, util.QcStateOid)
s := util.ParseQcStatem(ext.Value, util.IdEtsiPsd2Statem)
psd2, ok := s.(util.EtsiPsd2)
if !ok {
return &lint.LintResult{Status: lint.Fatal, Details: "parsed QC statement is not of type EtsiPsd2"}
}

// Check NCAName itself against psd2.Decoded (populated whenever the
// PSD2QcType SEQUENCE itself unmarshaled, even if e_qcstatem_psd2_valid's
// structural SIZE(1..256) check already flagged it) before falling back
// to s.GetErrorInfo()'s generic message, so this lint's own
// NCAName-specific Details take precedence over that structural check.
if util.IsPsd2CentralBankOrPublicAuthority(psd2.Decoded.RolesOfPSP) {
if psd2.Decoded.NCAName != "NA" {
return &lint.LintResult{Status: lint.Error, Details: "NCAName must be 'NA' for a PSD2 QcStatement declaring a PSP_CB or PSP_PA role"}
}
} else {
nameLen := utf8.RuneCountInString(psd2.Decoded.NCAName)
if nameLen == 0 {
return &lint.LintResult{Status: lint.Error, Details: "NCAName must not be empty"}
}
if nameLen > 256 {
return &lint.LintResult{Status: lint.Error, Details: "NCAName must be at most 256 characters"}
}
}

if s.GetErrorInfo() != "" {
return &lint.LintResult{Status: lint.Error, Details: s.GetErrorInfo()}
}
return &lint.LintResult{Status: lint.Pass}
}
48 changes: 48 additions & 0 deletions v3/lints/etsi/lint_qcstatem_psd2_ncaname_valid_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package etsi

/*
* ZLint Copyright 2026 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import (
"testing"

"github.com/zmap/zlint/v3/lint"
"github.com/zmap/zlint/v3/test"
)

func TestEtsiQcStatemPsd2NcaNameValid(t *testing.T) {
cases := map[string]struct {
status lint.LintStatus
details string // empty means "don't check Details"
}{
"QcStmtEtsiPsd2ValidCert01.pem": {status: lint.Pass},
"QcStmtEtsiPsd2NcaNameEmptyCert01.pem": {status: lint.Error, details: "NCAName must not be empty"},
"QcStmtEtsiPsd2NcaNameTooLongCert01.pem": {status: lint.Error, details: "NCAName must be at most 256 characters"},
"QcStmtEtsiPsd2NcaNamePspCbValidCert01.pem": {status: lint.Pass},
"QcStmtEtsiPsd2NcaNamePspPaValidCert01.pem": {status: lint.Pass},
"QcStmtEtsiPsd2NcaNamePspCbInvalidCert01.pem": {status: lint.Error,
details: "NCAName must be 'NA' for a PSD2 QcStatement declaring a PSP_CB or PSP_PA role"},
"QcStmtEtsiPsd2WrongEncodingCert01.pem": {status: lint.Error, details: "error with ASN.1 encoding, possibly a wrong ASN.1 string type was used"},
"QcStmtEtsiValidCert11.pem": {status: lint.NA},
}
for inputPath, tc := range cases {
out := test.TestLint("e_qcstatem_psd2_ncaname_valid", inputPath)
if out.Status != tc.status {
t.Errorf("%s: expected %s, got %s", inputPath, tc.status, out.Status)
}
if tc.details != "" && out.Details != tc.details {
t.Errorf("%s: expected details %q, got %q", inputPath, tc.details, out.Details)
}
}
}
42 changes: 42 additions & 0 deletions v3/testdata/QcStmtEtsiPsd2NcaNameEmptyCert01.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: ecdsa-with-SHA256
Issuer:
Validity
Not Before: Jan 1 00:00:00 2020 GMT
Not After : Jan 1 00:00:00 2030 GMT
Subject: CN = PSD2 NCAName Test Leaf
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:5e:79:45:e9:69:ae:23:1a:53:74:23:1f:5f:ac:
e7:1c:70:f4:d0:02:b4:61:74:dc:01:67:c8:5d:07:
d2:b2:87:9c:b7:be:6b:62:88:1c:86:23:c1:85:c3:
98:39:d0:40:23:3a:1f:6c:56:1c:97:2c:c4:0f:3b:
e6:12:f8:0e:03
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
qcStatements:
0+0)......'.0.0.0.......'....PSP_AS....ES-BDE
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:46:02:21:00:94:1d:4a:b1:4a:50:a6:a1:6a:f2:d5:39:c4:
e0:6f:10:6b:ae:37:18:3e:41:90:5b:c0:96:87:35:49:53:f9:
c7:02:21:00:d4:ff:ee:29:6c:43:a8:71:21:40:af:90:90:9c:
df:a4:46:ac:b9:8e:14:74:33:f4:f9:df:82:fb:82:4d:79:e6
-----BEGIN CERTIFICATE-----
MIIBXDCCAQGgAwIBAgIBAjAKBggqhkjOPQQDAjAAMB4XDTIwMDEwMTAwMDAwMFoX
DTMwMDEwMTAwMDAwMFowITEfMB0GA1UEAxMWUFNEMiBOQ0FOYW1lIFRlc3QgTGVh
ZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF55RelpriMaU3QjH1+s5xxw9NAC
tGF03AFnyF0H0rKHnLe+a2KIHIYjwYXDmDnQQCM6H2xWHJcsxA875hL4DgOjSzBJ
MAwGA1UdEwEB/wQCMAAwOQYIKwYBBQUHAQMELTArMCkGBgQAgZgnAjAfMBMwEQYH
BACBmCcBAQwGUFNQX0FTDAAMBkVTLUJERTAKBggqhkjOPQQDAgNJADBGAiEAlB1K
sUpQpqFq8tU5xOBvEGuuNxg+QZBbwJaHNUlT+ccCIQDU/+4pbEOocSFAr5CQnN+k
Rqy5jhR0M/T534L7gk155g==
-----END CERTIFICATE-----
42 changes: 42 additions & 0 deletions v3/testdata/QcStmtEtsiPsd2NcaNamePspCbInvalidCert01.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6 (0x6)
Signature Algorithm: ecdsa-with-SHA256
Issuer:
Validity
Not Before: Jan 1 00:00:00 2020 GMT
Not After : Jan 1 00:00:00 2030 GMT
Subject: CN = PSD2 NCAName Test Leaf
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:29:51:cc:1d:d0:6d:0e:7b:ea:03:23:a6:c8:f4:
13:92:5d:36:a3:bd:ce:b0:05:13:fa:3c:64:1b:be:
84:a9:23:9f:d3:b8:51:ba:2d:bb:15:8d:b2:32:0a:
48:fb:8d:e0:fe:46:4f:e7:30:a2:17:66:8e:42:b5:
16:0e:87:b2:bf
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
qcStatements:
0705......'.0+0.0.......'....PSP_CB..Banco de Espa..a..NA
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:44:02:20:08:76:c4:60:b3:bd:65:56:30:d8:20:0f:c1:5c:
96:1c:30:50:6a:e3:b8:2a:ac:31:7c:a6:69:68:c0:eb:3b:fa:
02:20:5d:a5:13:e2:38:39:d6:d7:24:d2:47:b8:57:ed:1c:69:
02:70:f5:4d:d1:7e:80:9e:28:05:17:b7:60:e8:40:4b
-----BEGIN CERTIFICATE-----
MIIBZjCCAQ2gAwIBAgIBBjAKBggqhkjOPQQDAjAAMB4XDTIwMDEwMTAwMDAwMFoX
DTMwMDEwMTAwMDAwMFowITEfMB0GA1UEAxMWUFNEMiBOQ0FOYW1lIFRlc3QgTGVh
ZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABClRzB3QbQ576gMjpsj0E5JdNqO9
zrAFE/o8ZBu+hKkjn9O4UbotuxWNsjIKSPuN4P5GT+cwohdmjkK1Fg6Hsr+jVzBV
MAwGA1UdEwEB/wQCMAAwRQYIKwYBBQUHAQMEOTA3MDUGBgQAgZgnAjArMBMwEQYH
BACBmCcBBQwGUFNQX0NCDBBCYW5jbyBkZSBFc3Bhw7FhDAJOQTAKBggqhkjOPQQD
AgNHADBEAiAIdsRgs71lVjDYIA/BXJYcMFBq47gqrDF8pmlowOs7+gIgXaUT4jg5
1tck0ke4V+0caQJw9U3RfoCeKAUXt2DoQEs=
-----END CERTIFICATE-----
42 changes: 42 additions & 0 deletions v3/testdata/QcStmtEtsiPsd2NcaNamePspCbValidCert01.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 4 (0x4)
Signature Algorithm: ecdsa-with-SHA256
Issuer:
Validity
Not Before: Jan 1 00:00:00 2020 GMT
Not After : Jan 1 00:00:00 2030 GMT
Subject: CN = PSD2 NCAName Test Leaf
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:64:ec:a7:f8:e8:eb:39:55:bc:96:5d:6c:97:e4:
64:5e:1d:a8:11:1c:3b:5b:fb:b9:1a:21:00:a1:51:
f9:c6:55:17:c1:d2:07:b2:41:39:9a:dc:43:7f:bf:
e6:a6:cb:14:ed:a6:00:71:97:c0:6f:b1:84:15:3f:
25:44:e9:9c:71
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
qcStatements:
0)0'......'.0.0.0.......'....PSP_CB..NA..NA
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:45:02:20:03:dd:d7:fb:ec:5f:c9:2f:bb:c9:bd:76:aa:7b:
fa:85:2a:fd:f9:ba:cb:37:9c:93:fd:32:31:80:2d:72:b2:1a:
02:21:00:f1:35:18:1b:88:5f:e0:46:82:cd:45:49:a2:a4:ff:
92:7e:f0:f7:2a:61:0f:fb:18:49:e7:6b:a1:10:de:d3:34
-----BEGIN CERTIFICATE-----
MIIBWDCB/6ADAgECAgEEMAoGCCqGSM49BAMCMAAwHhcNMjAwMTAxMDAwMDAwWhcN
MzAwMTAxMDAwMDAwWjAhMR8wHQYDVQQDExZQU0QyIE5DQU5hbWUgVGVzdCBMZWFm
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZOyn+OjrOVW8ll1sl+RkXh2oERw7
W/u5GiEAoVH5xlUXwdIHskE5mtxDf7/mpssU7aYAcZfAb7GEFT8lROmccaNJMEcw
DAYDVR0TAQH/BAIwADA3BggrBgEFBQcBAwQrMCkwJwYGBACBmCcCMB0wEzARBgcE
AIGYJwEFDAZQU1BfQ0IMAk5BDAJOQTAKBggqhkjOPQQDAgNIADBFAiAD3df77F/J
L7vJvXaqe/qFKv35uss3nJP9MjGALXKyGgIhAPE1GBuIX+BGgs1FSaKk/5J+8Pcq
YQ/7GEnna6EQ3tM0
-----END CERTIFICATE-----
42 changes: 42 additions & 0 deletions v3/testdata/QcStmtEtsiPsd2NcaNamePspPaValidCert01.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 5 (0x5)
Signature Algorithm: ecdsa-with-SHA256
Issuer:
Validity
Not Before: Jan 1 00:00:00 2020 GMT
Not After : Jan 1 00:00:00 2030 GMT
Subject: CN = PSD2 NCAName Test Leaf
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:1e:69:4a:94:58:0e:54:56:38:53:42:25:65:ac:
e7:10:3a:e3:45:92:0b:25:88:74:86:fb:eb:7c:1b:
90:42:95:2f:ab:0b:c0:67:f9:eb:0a:db:33:a4:f9:
33:79:a5:ec:37:4a:25:4b:57:d2:a2:78:e9:ac:4f:
3e:6d:16:83:5e
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
qcStatements:
0)0'......'.0.0.0.......'....PSP_PA..NA..NA
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:44:02:20:78:08:3a:82:3f:76:7c:ff:97:84:cb:c5:43:65:
bd:5f:d1:02:4b:a4:42:d1:d8:98:c5:30:1b:12:4e:bc:33:e8:
02:20:70:77:2f:7c:ad:c0:e9:d8:b6:87:64:2b:32:79:99:36:
c7:0f:ba:17:81:c5:0b:0a:dc:f1:49:26:0c:56:2b:8c
-----BEGIN CERTIFICATE-----
MIIBVzCB/6ADAgECAgEFMAoGCCqGSM49BAMCMAAwHhcNMjAwMTAxMDAwMDAwWhcN
MzAwMTAxMDAwMDAwWjAhMR8wHQYDVQQDExZQU0QyIE5DQU5hbWUgVGVzdCBMZWFm
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHmlKlFgOVFY4U0IlZaznEDrjRZIL
JYh0hvvrfBuQQpUvqwvAZ/nrCtszpPkzeaXsN0olS1fSonjprE8+bRaDXqNJMEcw
DAYDVR0TAQH/BAIwADA3BggrBgEFBQcBAwQrMCkwJwYGBACBmCcCMB0wEzARBgcE
AIGYJwEGDAZQU1BfUEEMAk5BDAJOQTAKBggqhkjOPQQDAgNHADBEAiB4CDqCP3Z8
/5eEy8VDZb1f0QJLpELR2JjFMBsSTrwz6AIgcHcvfK3A6di2h2QrMnmZNscPuheB
xQsK3PFJJgxWK4w=
-----END CERTIFICATE-----
47 changes: 47 additions & 0 deletions v3/testdata/QcStmtEtsiPsd2NcaNameTooLongCert01.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Signature Algorithm: ecdsa-with-SHA256
Issuer:
Validity
Not Before: Jan 1 00:00:00 2020 GMT
Not After : Jan 1 00:00:00 2030 GMT
Subject: CN = PSD2 NCAName Test Leaf
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:4e:3a:ec:ed:68:f3:e5:1f:a1:38:41:67:00:6e:
e3:1c:d3:be:cf:fc:6e:b3:fe:56:2d:2d:db:04:a7:
78:d9:99:71:a2:f3:6a:fb:78:6d:19:6d:2a:cc:f4:
6f:1a:e1:8f:da:59:e8:d5:c7:f8:08:93:26:5b:30:
f4:d1:2c:7a:70
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
qcStatements:
0..20.........'.0.."0.0.......'....PSP_AS....AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..ES-BDE
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:45:02:21:00:86:49:31:16:fb:56:52:da:54:6c:9a:a1:ac:
93:fb:fe:05:d2:3b:42:50:98:2e:a6:a2:14:6e:a2:23:3c:b2:
4c:02:20:1d:96:4c:15:7a:97:c1:8d:a4:57:d5:f5:ea:d6:3c:
a2:2d:5b:bc:9d:ac:58:e7:99:cc:39:ce:3d:f0:0c:0d:69
-----BEGIN CERTIFICATE-----
MIICbDCCAhKgAwIBAgIBAzAKBggqhkjOPQQDAjAAMB4XDTIwMDEwMTAwMDAwMFoX
DTMwMDEwMTAwMDAwMFowITEfMB0GA1UEAxMWUFNEMiBOQ0FOYW1lIFRlc3QgTGVh
ZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE467O1o8+UfoThBZwBu4xzTvs/8
brP+Vi0t2wSneNmZcaLzavt4bRltKsz0bxrhj9pZ6NXH+AiTJlsw9NEsenCjggFa
MIIBVjAMBgNVHRMBAf8EAjAAMIIBRAYIKwYBBQUHAQMEggE2MIIBMjCCAS4GBgQA
gZgnAjCCASIwEzARBgcEAIGYJwEBDAZQU1BfQVMMggEBQUFBQUFBQUFBQUFBQUFB
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
QUEMBkVTLUJERTAKBggqhkjOPQQDAgNIADBFAiEAhkkxFvtWUtpUbJqhrJP7/gXS
O0JQmC6mohRuoiM8skwCIB2WTBV6l8GNpFfV9erWPKItW7ydrFjnmcw5zj3wDA1p
-----END CERTIFICATE-----
4 changes: 3 additions & 1 deletion v3/util/oid.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ var (
QEVCPwPolicyOID = asn1.ObjectIdentifier{0, 4, 0, 194112, 1, 4}
QNCPwPolicyOID = asn1.ObjectIdentifier{0, 4, 0, 194112, 1, 5}
QNCPwgenPolicyOID = asn1.ObjectIdentifier{0, 4, 0, 194112, 1, 6}
IdEtsiPsd2Statem = asn1.ObjectIdentifier{0, 4, 0, 19495, 2} // ETSI TS 119 495 V1.1.2, Annex A: id-etsi-psd2-qcStatement
IdEtsiPsd2Statem = asn1.ObjectIdentifier{0, 4, 0, 19495, 2} // ETSI TS 119 495 V1.1.2, Annex A: id-etsi-psd2-qcStatement
IdEtsiPsd2RolePspCb = asn1.ObjectIdentifier{0, 4, 0, 19495, 1, 5} // ETSI TS 119 495, Annex A: id-psd2-role-psp-cb (Central Bank)
IdEtsiPsd2RolePspPa = asn1.ObjectIdentifier{0, 4, 0, 19495, 1, 6} // ETSI TS 119 495, Annex A: id-psd2-role-psp-pa (Public authority)
)

const (
Expand Down
13 changes: 13 additions & 0 deletions v3/util/qc_stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ type EtsiPsd2 struct {
Decoded PSD2QcType
}

// IsPsd2CentralBankOrPublicAuthority reports whether roles declares a PSP_CB
// (Central Bank) or PSP_PA (Public authority) role, per ETSI TS 119 495
// Annex A. Certificates declaring either role are subject to the
// GEN-5.2.3-1A/GEN-5.2.3-5 "NA" carve-out for NCAName/NCAId.
func IsPsd2CentralBankOrPublicAuthority(roles []RoleOfPSP) bool {
for _, role := range roles {
if role.RoleOfPspOid.Equal(IdEtsiPsd2RolePspCb) || role.RoleOfPspOid.Equal(IdEtsiPsd2RolePspPa) {
return true
}
}
return false
}

func AppendToStringSemicolonDelim(this *string, s string) {
if len(*this) > 0 && len(s) > 0 {
(*this) += "; "
Expand Down
Loading
Loading