I want to create mock CA and set QCStatements extension, but I can't find any information about setting it using OpenSSL. I was looking about I found some old topics where people looking for this information, but no one answer. Is this possible to set QCStatements using openSSL?
3 Answers
It is possible with pure openssl. You have to create configuration for the signing request with all required qcStatements
information and then sing the certificate copying the requested extension.
Sample configuration file
[req]
distinguished_name = req_distinguished_name
req_extensions = qcStatements
[req_distinguished_name]
[qcStatements]
1.3.6.1.5.5.7.1.3=ASN1:SEQUENCE:qcStatement
[qcStatement]
etsiQcsCompliance=SEQUENCE:etsiQcsCompliance
qcs-QcPDS=SEQUENCE:qcs-QcPDS
id-qc-statement=SEQUENCE:id-qc-statement
qcs-QcType=SEQUENCE:qcs-QcType
[etsiQcsCompliance]
statementId=OID:0.4.0.1862.1.1
[qcs-QcPDS]
statementId=OID:0.4.0.1862.1.5
QcPDS-List=SEQUENCE:QcPDS-List
[QcPDS-List]
QcPDS1=SEQUENCE:QcPDS1
[QcPDS1]
url=IA5STRING:https://example.org/pkidisclosure
description=PRINTABLESTRING:example
[id-qc-statement]
statementId=OID:0.4.0.19495.2
statementInfo=SEQUENCE:id-qc-statement-Info
[id-qc-statement-Info]
rolesOfPSP=SEQUENCE:rolesOfPSP
nCAName=UTF8String:Dummy Financial Supervision Authority
nCAId=UTF8String:XX-DFSA
[rolesOfPSP]
PSP_AI=SEQUENCE:PSP_AI
PSP_AS=SEQUENCE:PSP_AS
PSP_PI=SEQUENCE:PSP_PI
PSP_IC=SEQUENCE:PSP_IC
[PSP_AI]
roleOfPspOid=OID:0.4.0.19495.1.3
roleOfPspName=UTF8String:PSP_AI
[PSP_AS]
roleOfPspOid=OID:0.4.0.19495.1.1
roleOfPspName=UTF8String:PSP_AS
[PSP_PI]
roleOfPspOid=OID:0.4.0.19495.1.2
roleOfPspName=UTF8String:PSP_PI
[PSP_IC]
roleOfPspOid=OID:0.4.0.19495.1.4
roleOfPspName=UTF8String:PSP_IC
[qcs-QcType]
statementId=OID:0.4.0.1862.1.6
statementInfo=SEQUENCE:qcs-QcType-Info
[qcs-QcType-Info]
qct-esign=OID:0.4.0.1862.1.6.1
qct-eseal=OID:0.4.0.1862.1.6.2
qct-web=OID:0.4.0.1862.1.6.3
You have to apply configuration to signing request
openssl req -new -key dummy.key -out dummy.csr -subj /C=XX/CN=dummy -config qcstatements.conf
And then sign with option to copy extensions from request inside CA configuration file.
copy_extensions = copy

- 209
- 2
- 5
Specil thanks to AGrzes - You really got me on the right track.
It took me a lot of searching to get through all of these related standards, so I thought I would help and post here to save someone the trouble.
When I am doing ASN.1 work, I'm usually perusing https://censys.io/certificates to check if my code matches existing certificates. Always saves me time. Take note of how many certificates your query results in- people make mistakes, so you might be headed down the wrong track.
Anyways, my openssl-RFC3739.cnf:
#Qualified Certificate Profiles / Payment Services Directive / ETSI / eIDAS
#TODO: implement: biometricInfo: typeOfBiometricData = OID:(finger/palm/retina/voice OID under my_pen OID arc)
#TEST: \
export OPENSSL_CONF=openssl-RFC3739.cnf; #use this conf \
openssl asn1parse -genstr OID:1.3.6.1.5.5.7.1.3; #check OID support \
openssl req -x509 -nodes -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -keyout key.pem -out cert.pem -batch; #generate public/prive keys \
openssl asn1parse -in cert.pem | sed -n '/qcStatements/{n;s/.*://p}' | xxd -r -p | openssl asn1parse -inform DER -i; #show qcStatements \
openssl asn1parse -in cert.pem | sed -n '/Biometric Info/{n;s/.*://p}' | xxd -r -p | openssl asn1parse -inform DER -i; #shox biometricInfo \
openssl asn1parse -in cert.pem | sed -n '/X509v3 Subject Directory Attributes/{n;s/.*://p}' | xxd -r -p | openssl asn1parse -inform DER -i; #show subjectDirectoryAttributes \
openssl asn1parse -in cert.pem | sed -n '/cabfOrganizationIdentifier/{n;s/.*://p}' | xxd -r -p | openssl asn1parse -inform DER -i; #show cabfOrganizationIdentifier \
#https://censys.io/certificates?q=parsed.unknown_extensions.id%3A+1.3.6.1.5.5.7.1.3 #example certs using this OID
#ETSI EN 319 412-1 V1.4.2 (2020-07) - https://www.etsi.org/deliver/etsi_en/319400_319499/31941201/01.04.02_20/en_31941201v010402a.pdf
#ETSI EN 319 412-2 V2.2.1 (2020-07) - https://www.etsi.org/deliver/etsi_en/319400_319499/31941202/02.02.01_60/en_31941202v020201p.pdf
#ETSI EN 319 412-3 V1.2.1 (2020-07) - https://www.etsi.org/deliver/etsi_en/319400_319499/31941203/01.02.01_60/en_31941203v010201p.pdf
#ETSI EN 319 412-4 V1.1.1 (2016-02) - https://www.etsi.org/deliver/etsi_en/319400_319499/31941204/01.01.01_60/en_31941204v010101p.pdf
#ETSI EN 319 412-5 V2.3.1 (2020-04) - https://www.etsi.org/deliver/etsi_en/319400_319499/31941205/02.03.01_60/en_31941205v020301p.pdf
#ETSI EN 319 411-1 V1.2.0 (2017-08) - https://www.etsi.org/deliver/etsi_EN/319400_319499/31941101/01.02.00_20/en_31941101v010200a.pdf
#ETSI TS 119 495 V1.4.1 (2019-11) - https://www.etsi.org/deliver/etsi_ts/119400_119499/119495/01.04.01_60/ts_119495v010401p.pdf
#ETSI TS 101 456 V1.4.3 (2007-05) - https://www.etsi.org/deliver/etsi_ts/101400_101499/101456/01.04.03_60/ts_101456v010403p.pdf
#VARIABLES - Defaults
SSL_url_0 = example.com
SSL_url_1 = secure.example.com
SSL_organizationName_0 = Example Company Limited
SSL_organizationName_1 = Công Ty Trách Nhiệm Hữu Hạn Example
SSL_countryName = VN
#SSL_countryName_1 = CA
SSL_stateOrProvinceName = Hà Nội
SSL_nCA = EXAMPLE
SSL_nCAId = 12345678
SSL_currency = VND
openssl_conf = RFC3739_init
#oid_section = RFC3739_OIDs
[RFC3739_init]
oid_section = RFC3739_OIDs
[RFC3739_OIDs]
#biometricInfo = 1.3.6.1.5.5.7.1.2 #id-pe-biometricInfo
#qcStatements = 1.3.6.1.5.5.7.1.3 #id-pe-qcStatements
#id-qcs = 1.3.6.1.5.5.7.11 #qcs
#id-qcs-pkixQCSyntax-v1 = 1.3.6.1.5.5.7.11.1 #qcs-pkixQCSyntax-v1
id-qcs-pkixQCSyntax-v2 = 1.3.6.1.5.5.7.11.2 #qcs-pkixQCSyntax-v2
cabfOrganizationIdentifier = 2.23.140.3.1 #cabforganization_identifier
#qualified-certificate-policies - ETSI TS 101 456
#qualified-certificate-policies = 0.4.0.1456 #id-etsi-qualified-certificate-policies
qcp-public-with-sscd = 0.4.0.1456.1
qcp-public = 0.4.0.1456.2
#id-etsi-qcStatements - ETSI EN 319 412-5
#qc-profile = 0.4.0.1862 #etsi-qc-profile eIDAS PSD2
#id-mod-qc-profile-2 = 0.4.0.1862.0.2
#id-etsi-qcStatements = 0.4.0.1862.1 #etsi-qcStatements
qcs-qcCompliance = 0.4.0.1862.1.1 #qcCompliance
qcs-qcLimitValue = 0.4.0.1862.1.2 #qcLimitValue
qcs-qcRetentionPeriod = 0.4.0.1862.1.3 #qcRetentionPeriod - int years
qcs-QcSSCD = 0.4.0.1862.1.4 #qcSSCD - Secure Signature Creation Device (SSCD)
qcs-qcPDS = 0.4.0.1862.1.5 #qcPDS - url
qcs-qcCClegislation = 0.4.0.1862.1.7 #qcCClegislation
qcs-qcType = 0.4.0.1862.1.6 #qcType
qct-eSign = 0.4.0.1862.1.6.1
qct-eSeal = 0.4.0.1862.1.6.2
qct-web = 0.4.0.1862.1.6.3
#other-certificate-policies - ETSI EN 319 411-1
#other-certificate-policies = 0.4.0.2042.1 #id-etsi-other-certificate-policies
ncp = 0.4.0.2042.1.1 #normalized-certificate-policy
ncpplus = 0.4.0.2042.1.2 #normalized-secure-certificate-policy
lcp = 0.4.0.2042.1.3 #lightweight-certificate-policy
evcp = 0.4.0.2042.1.4 #extended-validation-certificate-policy
evcpplus = 0.4.0.2042.1.5 #extended-validation-secure-certificate-policy
dvcp = 0.4.0.2042.1.6 #domain-validation-certificate-policy
ovcp = 0.4.0.2042.1.7 #organization-validation-certificate-policy
ivcp = 0.4.0.2042.1.8 #individual-validation-certificate-policy
#id-etsi-psd2 - ETSI TS 119 495
#etsi-psd2 = 0.4.0.19495
#etsi-psd2-roles = 0.4.0.19495.1
id-psd2-role-psp-as = 0.4.0.19495.1.1 #psp-account-servicing
id-psd2-role-psp-pi = 0.4.0.19495.1.2 #psp-payment-initiation
id-psd2-role-psp-ai = 0.4.0.19495.1.3 #psp-account-information
id-psd2-role-psp-ic = 0.4.0.19495.1.4 #psp-issuing-card-payment-instruction
id-etsi-psd2-qcStatement = 0.4.0.19495.2 #etsi-psd2-qcStatement, qcPDS2, qcs-qcPDS2
#etsi-psd2-policy = 0.4.0.19495.3 #psd2-policy
qcp-web-psd2 = 0.4.0.19495.3.1 #qcp-w-psd2
#qcs-policy-identifiers - ETSI EN 319 412-2
#id-etsi-qcs-policy-identifiers = 0.4.0.194112.1 #qcs-policy-identifiers
qcp-natural = 0.4.0.194112.1.0 #qcp-l - natural person
qcp-legal = 0.4.0.194112.1.1 #qcp-n - legal person
qcp-natural-qscd = 0.4.0.194112.1.2 #qcp-n-qscd - natural person seal creation device
qcp-legal-qscd = 0.4.0.194112.1.3 #qcp-l-qscd - legal person seal creation device
qcp-web = 0.4.0.194112.1.4 #qcp-w - website
#qcs-semantics-identifiers - ETSI EN 319 412-1
#id-etsi-qcs-semantics-identifiers = 0.4.0.194121.1 #qcs-semantics-identifiers
id-etsi-qcs-SemanticsId-Natural = 0.4.0.194121.1.1 #qcs-SemanticsId-Natural, eSign
id-etsi-qcs-SemanticsId-Legal = 0.4.0.194121.1.2 #qcs-SemanticsId-Legal, eSeal
id-etsi-qcs-SemanticsId-eIDASNatural = 0.4.0.194121.1.3 #qcs-SemanticsId-eIDASNatural, eSign
id-etsi-qcs-SemanticsId-eIDASLegal = 0.4.0.194121.1.4 #qcs-SemanticsId-eIDASLegal, eSeal
[req]
distinguished_name = RFC3739_DNs
x509_extensions = RFC3739_ext
[RFC3739_DNs]
description = RFC3739
description_default = RFC3739
[RFC3739_ext]
certificatePolicies = qcp-web,qcp-legal,qcp-legal-qscd,evcp,evcpplus,qcp-web-psd2,qcp-public
qcStatements = ASN1:SEQ:qcStatements
subjectDirectoryAttributes = ASN1:SEQ:personalDataAttributes #id-pda
biometricInfo = ASN1:SEQ:biometricSyntax
cabfOrganizationIdentifier = ASN1:SEQ:cabfOrganizationIdentifier
[cabfOrganizationIdentifier]
scheme = PRINTABLE:PSD
country = PRINTABLE:${ENV::SSL_countryName}
state = IMP:0,UTF8:${ENV::SSL_stateOrProvinceName}
nCAId = UTF8:${ENV::SSL_nCA}-${ENV::SSL_nCAId}
[biometricSyntax]
0.biometricData = SEQ:biometricData-0
1.biometricData = SEQ:biometricData-1
[biometricData-0]
typeOfBiometricData = INT:0 #picture INT:0, handwritten-signature INT:1, biometricDataOid
hashAlgorithm = SEQWRAP,OID:SHA256
biometricDataHash = OCT:38CF6A36FDE77FC193E224834AE353CEA31302D9B681FB39C11622D63A5ADB99
sourceDataUri = IA5:https://${ENV::SSL_url_1}/ca/user/${biometricDataHash}.jpg #optional
[biometricData-1]
typeOfBiometricData = INT:1
hashAlgorithm = SEQWRAP,OID:SHA256
biometricDataHash = OCT:38CF6A36FDE77FC193E224834AE353CEA31302D9B681FB39C11622D63A5ADB99
sourceDataUri = IA5:https://${ENV::SSL_url_1}/ca/user/${biometricDataHash}.jpg #optional
[personalDataAttributes]
dateOfBirth = SEQ:pda-dateOfBirth
placeOfBirth = SEQ:pda-placeOfBirth
gender = SEQ:pda-gender
CountryOfCitizenship = SEQ:pda-countryOfCitizenship #can be specified multiple times
0.CountryOfResidence = SEQ:pda-countryOfResidence-0 #can be specified multiple times
1.CountryOfResidence = SEQ:pda-countryOfResidence-1
[pda-dateOfBirth]
oid = OID:id-pda-dateOfBirth
value = SETWRAP,GENTIME:19870716000000Z #GeneralizedTime - YYYYMMDDHHMMSS.SZ
[pda-placeOfBirth]
oid = OID:id-pda-placeOfBirth
value = SETWRAP,UTF8:my hospital, address, province, CA #Should be DirectoryString = choice (3) = utf8
[pda-gender]
oid = OID:id-pda-gender
value = SETWRAP,PRINTABLE:M #PrintableString - M,m,F,f
[pda-countryOfCitizenship]
oid = OID:id-pda-countryOfCitizenship
value = SETWRAP,PRINTABLE:CA #PrintableString - ISO 3166 Country Code - 2 digits
[pda-countryOfResidence-0]
oid = OID:id-pda-countryOfResidence
value = SETWRAP,PRINTABLE:${ENV::SSL_countryName} #PrintableString - ISO 3166 Country Code - 2 digits
[pda-countryOfResidence-1]
oid = OID:id-pda-countryOfResidence
value = SETWRAP,PRINTABLE:CA #PrintableString - ISO 3166 Country Code - 2 digits
[qcStatements]
qcpkixQCSyntax = SEQ:qcs-qcpkixQCSyntax #SEQWRAP,OID:id-qcs-pkixQCSyntax-v2 #id-qcs-pkixQCSyntax-v1
qcCompliance = SEQWRAP,OID:qcs-qcCompliance
qcLimitValue = SEQ:qcs-qcLimitValue
qcRetentionPeriod = SEQ:qcs-qcRetentionPeriod
qcSSCD = SEQWRAP,OID:qcs-QcSSCD
qcPDS = SEQ:qcs-qcPDS
qcType = SEQ:qcs-qcType
qcCClegislation = SEQ:qcs-qcCClegislation
qcPDS2 = SEQ:qcs-qcPDS2
[qcs-qcpkixQCSyntax]
statementId = OID:id-qcs-pkixQCSyntax-v2 #id-qcs-pkixQCSyntax-v1
statementInfo = SEQWRAP,OID:id-etsi-qcs-SemanticsId-Legal #can have multiple
[qcs-qcLimitValue]
statementId = OID:qcs-qcLimitValue
monetaryValue = SEQ:qcLimitValue
[qcLimitValue]
limitCurrency = PRINTABLE:${ENV::SSL_currency} #or INT:(0-999) ISO 4217
limitAmount = INT:1000000
limitExponent = INT:10 #value = amount * 10^exponent
[qcs-qcRetentionPeriod]
statementId = OID:qcs-qcRetentionPeriod
retentionYears = INT:15
[qcs-qcPDS]
statementId = OID:qcs-qcPDS
qcPDS = SEQ:qcPDS
[qcPDS]
0.PDSLocation = SEQ:PDSLocation-0
1.PDSLocation = SEQ:PDSLocation-1
2.PDSLocation = SEQ:PDSLocation-2
3.PDSLocation = SEQ:PDSLocation-3
[PDSLocation-0]
url = IA5:https://${ENV::SSL_url_0}/ca/pds
lang = PRINTABLE:en
[PDSLocation-1]
url = IA5:https://${ENV::SSL_url_0}/ca/pds
lang = PRINTABLE:vi
[PDSLocation-2]
url = IA5:https://${ENV::SSL_url_1}/ca/pds
lang = PRINTABLE:en
[PDSLocation-3]
url = IA5:https://${ENV::SSL_url_1}/ca/pds
lang = PRINTABLE:vi
[qcs-qcType]
statementId = OID:qcs-qcType
typeName = SEQ:qcType
[qcType]
0.qcType = OID:qct-eSign
1.qcType = OID:qct-eSeal
2.qcType = OID:qct-web
[qcs-qcCClegislation]
statementId = OID:qcs-qcCClegislation
countryName = SEQ:qcCClegislation
[qcCClegislation]
0.countryName = PRINTABLE:${ENV::SSL_countryName}
1.countryName = PRINTABLE:CA
[qcs-qcPDS2]
statementId = OID:id-etsi-psd2-qcStatement
statementInfo = SEQ:qcPDS2
[qcPDS2]
rolesOfPSP = SEQ:PSProles
nCAName = UTF8:${ENV::SSL_organizationName_0} / ${ENV::SSL_organizationName_1}
nCAId = UTF8:PSD${ENV::SSL_countryName}-${ENV::SSL_nCA}-${ENV::SSL_nCAId} #VN-TWOEIGHT-1234567890
[PSProles]
0.PSProle = SEQ:PSProle-0
1.PSProle = SEQ:PSProle-1
2.PSProle = SEQ:PSProle-2
3.PSProle = SEQ:PSProle-3
[PSProle-0]
roleOfPspOid = OID:id-psd2-role-psp-as
roleOfPspName = UTF8:PSP_AS
[PSProle-1]
roleOfPspOid = OID:id-psd2-role-psp-pi
roleOfPspName = UTF8:PSP_PI
[PSProle-2]
roleOfPspOid = OID:id-psd2-role-psp-ai
roleOfPspName = UTF8:PSP_AI
[PSProle-3]
roleOfPspOid = OID:id-psd2-role-psp-ic
roleOfPspName = UTF8:PSP_IC
I'll keep an eye open for comments and edit if anything is incorrect.

- 121
- 1
- 6