Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IllegalArgumentException: Unknown object id - DNQ - passed to distinguished name #1622

Open
ralfhauser opened this issue Apr 10, 2024 · 9 comments
Assignees

Comments

@ralfhauser
Copy link

ralfhauser commented Apr 10, 2024

A qualified Italian QES cert seems to throw this error

java.lang.IllegalArgumentException: Unknown object id - DNQ - passed to distinguished name
        at org.bouncycastle.asn1.x500.style.IETFUtils.decodeAttrName(Unknown Source)
        at org.bouncycastle.asn1.x500.style.BCStyle.attrNameToOID(Unknown Source)
        at org.bouncycastle.asn1.x500.style.IETFUtils.rDNsFromString(Unknown Source)
        at org.bouncycastle.asn1.x500.style.BCStyle.fromString(Unknown Source)

dnq.pem.txt

    at org.bouncycastle.asn1.x500.X500Name.<init>(Unknown Source)
    at org.bouncycastle.asn1.x500.X500Name.<init>(Unknown Source)`

Are they wrong ?


Edited for clarity by @cipherboy.

@cipherboy
Copy link
Collaborator

cipherboy commented Apr 10, 2024

@ralfhauser Can you give sample code of what you're attempting to do?

It appears our code expects the identifier dnqualifier rather than dnq for this value, if you're using the RFC 4519 class rather than the BCStyle class.

This matches OpenSSL's output for this certificate:

$ openssl x509 -in ~/Downloads/dnq.pem.txt -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4112325213882364794 (0x3911e9fe7657337a)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = IT, O = Namirial S.p.A./02046570426, OU = Certification Authority, CN = Namirial CA Firma Qualificata
        Validity
            Not Before: Dec 19 10:35:00 2022 GMT
            Not After : Dec 17 23:00:00 2025 GMT
        Subject: C = IT, SN = VINATTIERI, GN = GIACOMO, serialNumber = TINIT-VNTGCM75A21D612F, CN = VINATTIERI GIACOMO, dnQualifier = LOVG2022121631199701

... snip ...

However, it does appear to be missing from our BCStyle class... so it could be that it might not work with BCStyle and dnQualifier either, in which case we can fix it. :-)

Are you aware of a reference calling this dnq over dnqualifier?

@cipherboy cipherboy self-assigned this Apr 10, 2024
@ralfhauser
Copy link
Author

Hi Alexander,
Thanks for the quick reply,
I just do
X500Principal java.security.cert.X509Certificate.getSubjectX500Principal()
an then I get the IllegalArgumentException

@cipherboy
Copy link
Collaborator

@ralfhauser Interesting... What version of BC are you running?

I get the following:

Code
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Main {
    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        StringReader sr = new StringReader("-----BEGIN CERTIFICATE-----\nMIIF+jCCBOKgAwIBAgIIORHp/nZXM3owDQYJKoZIhvcNAQELBQAwfTELMAkGA1UE\nBhMCSVQxJDAiBgNVBAoMG05hbWlyaWFsIFMucC5BLi8wMjA0NjU3MDQyNjEgMB4G\nA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJjAkBgNVBAMMHU5hbWlyaWFs\nIENBIEZpcm1hIFF1YWxpZmljYXRhMB4XDTIyMTIxOTEwMzUwMFoXDTI1MTIxNzIz\nMDAwMFowgZExCzAJBgNVBAYTAklUMRMwEQYDVQQEDApWSU5BVFRJRVJJMRAwDgYD\nVQQqDAdHSUFDT01PMR8wHQYDVQQFExZUSU5JVC1WTlRHQ003NUEyMUQ2MTJGMRsw\nGQYDVQQDDBJWSU5BVFRJRVJJIEdJQUNPTU8xHTAbBgNVBC4TFExPVkcyMDIyMTIx\nNjMxMTk5NzAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhcdxxuHh\nxhimZ5OWvGS1JPiDAxzwUr1f5TMEyzEdr0MqkG+DCcl0dmLhChya9j4WxaSgVkDP\n+YF8p+Ki/bRaQo/7UrA6Jr3q1Q3IPTrk2py5dsrhh9BlYjCBnNvkpZFqJyrPjn0B\ncyr3AgPslpqoMr6Hwy8z1OjqbpI24rv14XpIOfYBDb7ZO/mcVWEKR99Szbo+zI5b\n1k0mfNx9YErOiNoNCnzVz/n5cKKTSK8j/MQfznALyTALJNvoMVgf+iUVYOnDtloT\nWnnE7ro2KmHxjhrn0Sy7mLDe6LiE7rdlsZ35H5KuPJ8JHKaxbliu6ZHl4vyn5N+j\nc/Y6yw2OhybD/QIDAQABo4ICZzCCAmMwgZwGCCsGAQUFBwEBBIGPMIGMMFEGCCsG\nAQUFBzAChkVodHRwczovL2RvY3MubmFtaXJpYWx0c3AuY29tL2RvY3VtZW50cy9O\nYW1pcmlhbENBRmlybWFRdWFsaWZpY2F0YS5jcnQwNwYIKwYBBQUHMAGGK2h0dHA6\nLy9vY3NwLm5hbWlyaWFsdHNwLmNvbS9vY3NwL2NlcnRzdGF0dXMwHQYDVR0OBBYE\nFMT24uLpEFwHzv+KAGTrpaBG47OdMB8GA1UdIwQYMBaAFGP97eaMYkdIz+oJQXN2\nEeJkYnsQMIHNBggrBgEFBQcBAwSBwDCBvTAIBgYEAI5GAQEwCwYGBACORgEDAgEU\nMAgGBgQAjkYBBDATBgYEAI5GAQYwCQYHBACORgEGATCBhAYGBACORgEFMHowOxY1\naHR0cHM6Ly9kb2NzLm5hbWlyaWFsdHNwLmNvbS9kb2N1bWVudHMvUERTL1BEU19l\nbi5wZGYTAmVuMDsWNWh0dHBzOi8vZG9jcy5uYW1pcmlhbHRzcC5jb20vZG9jdW1l\nbnRzL1BEUy9QRFNfaXQucGRmEwJpdDBaBgNVHSAEUzBRMAkGBwQAi+xAAQIwOgYL\nKwYBBAGCmmsBAQIwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9kb2NzLm5hbWlyaWFs\ndHNwLmNvbS8wCAYGBACPegECMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmwu\nbmFtaXJpYWx0c3AuY29tL0Zpcm1hQ2VydGFRdWFsaWZpY2F0YTEuY3JsMA4GA1Ud\nDwEB/wQEAwIGQDANBgkqhkiG9w0BAQsFAAOCAQEASrkvsTg+7AJCvU9+KYqnjrcl\n5L8VZhKrDWFHAeQOGK+vBoRuDXqmrmuaSaiJbKGY6A7VL4SSV1SeJYAIKR4FdyDR\nr6XH5Hcw5b8k5IjcFU9a5oUMbRv7ie2A6vluRoHV9njDcBasKoAs3a/iYtptq2t3\n0TEXdadj8NPlCYZsZaptBUhIZGnpKmYye8UP/g98Sy955PxEhMiqfL53iwp4FdBJ\n/Asx0acMTwVB1sok+LxNAnLAufhj6xvMaXPLoJ8E23OlrgOle9baRKhKO+TfNamw\nton3fJUp2/dvGc5GEvp9gEN0sQSksPLd3y8ZePsauWWLkO0H89ykEnnKeUYOUA==\n-----END CERTIFICATE-----\n");
        PEMParser p = new PEMParser(sr);

        Object o = p.readObject();
        System.out.println("Got: " + o);

        X509CertificateHolder bcCert = (X509CertificateHolder)o;
        System.out.println("BC Cert: " + bcCert);

        X500Name bcSubj = bcCert.getSubject();
        System.out.println("BC Subject: " + bcSubj);

        byte[] data = bcCert.getEncoded();
        CertificateFactory cf = CertificateFactory.getInstance("X509", "BC");
        Certificate jCert = cf.generateCertificate(new ByteArrayInputStream(data));
        System.out.println("Java Cert:" + jCert);

        X509Certificate xCert = (X509Certificate)jCert;
        System.out.println("X509 Java Cert:" + xCert);

        X500Principal xPrinc = xCert.getSubjectX500Principal();
        System.out.println("X500 Principal: " + xPrinc);
    }
}
Terminal Output
Got: org.bouncycastle.cert.X509CertificateHolder@9b27e087
BC Cert: org.bouncycastle.cert.X509CertificateHolder@9b27e087
BC Subject: C=IT,SURNAME=VINATTIERI,GIVENNAME=GIACOMO,SERIALNUMBER=TINIT-VNTGCM75A21D612F,CN=VINATTIERI GIACOMO,DN=LOVG2022121631199701
Java Cert:  [0]         Version: 3
         SerialNumber: 4112325213882364794
             IssuerDN: C=IT,O=Namirial S.p.A./02046570426,OU=Certification Authority,CN=Namirial CA Firma Qualificata
           Start Date: Mon Dec 19 05:35:00 EST 2022
           Final Date: Wed Dec 17 18:00:00 EST 2025
            SubjectDN: C=IT,SURNAME=VINATTIERI,GIVENNAME=GIACOMO,SERIALNUMBER=TINIT-VNTGCM75A21D612F,CN=VINATTIERI GIACOMO,DN=LOVG2022121631199701
           Public Key: RSA Public Key [64:4c:b7:6e:53:05:e9:0a:11:1e:33:72:e2:06:18:79:84:72:e5:b2],[56:66:d1:a4]
        modulus: 85c771c6e1e1c618a6679396bc64b524f883031cf052bd5fe53304cb311daf432a906f8309c9747662e10a1c9af63e16c5a4a05640cff9817ca7e2a2fdb45a428ffb52b03a26bdead50dc83d3ae4da9cb976cae187d0656230819cdbe4a5916a272acf8e7d01732af70203ec969aa832be87c32f33d4e8ea6e9236e2bbf5e17a4839f6010dbed93bf99c55610a47df52cdba3ecc8e5bd64d267cdc7d604ace88da0d0a7cd5cff9f970a29348af23fcc41fce700bc9300b24dbe831581ffa251560e9c3b65a135a79c4eeba362a61f18e1ae7d12cbb98b0dee8b884eeb765b19df91f92ae3c9f091ca6b16e58aee991e5e2fca7e4dfa373f63acb0d8e8726c3fd
public exponent: 10001

  Signature Algorithm: SHA256WITHRSA
            Signature: 4ab92fb1383eec0242bd4f7e298aa78eb725e4bf
                       156612ab0d614701e40e18afaf06846e0d7aa6ae
                       6b9a49a8896ca198e80ed52f849257549e258008
                       291e057720d1afa5c7e47730e5bf24e488dc154f
                       5ae6850c6d1bfb89ed80eaf96e4681d5f678c370
                       16ac2a802cddafe262da6dab6b77d1311775a763
                       f0d3e509866c65aa6d0548486469e92a66327bc5
                       0ffe0f7c4b2f79e4fc4484c8aa7cbe778b0a7815
                       d049fc0b31d1a70c4f0541d6ca24f8bc4d0272c0
                       b9f863eb1bcc6973cba09f04db73a5ae03a57bd6
                       da44a84a3be4df35a9b0b689f77c9529dbf76f19
                       ce4612fa7d804374b104a4b0f2dddf2f1978fb1a
                       b9658b90ed07f3dca41279ca79460e50
       Extensions: 
                       critical(false) 1.3.6.1.5.5.7.1.1 value = Sequence
    Sequence
        ObjectIdentifier(1.3.6.1.5.5.7.48.2)
        Tagged [CONTEXT 6] IMPLICIT 
            DER Octet String[69] 
    Sequence
        ObjectIdentifier(1.3.6.1.5.5.7.48.1)
        Tagged [CONTEXT 6] IMPLICIT 
            DER Octet String[43] 

                       critical(false) 2.5.29.14 value = DER Octet String[20] 

                       critical(false) 2.5.29.35 value = Sequence
    Tagged [CONTEXT 0] IMPLICIT 
        DER Octet String[20] 

                       critical(false) 1.3.6.1.5.5.7.1.3 value = Sequence
    Sequence
        ObjectIdentifier(0.4.0.1862.1.1)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.3)
        Integer(20)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.4)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.6)
        Sequence
            ObjectIdentifier(0.4.0.1862.1.6.1)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.5)
        Sequence
            Sequence
                IA5String(https://docs.namirialtsp.com/documents/PDS/PDS_en.pdf) 
                PrintableString(en) 
            Sequence
                IA5String(https://docs.namirialtsp.com/documents/PDS/PDS_it.pdf) 
                PrintableString(it) 

                       critical(false) 2.5.29.32 value = Sequence
    Sequence
        ObjectIdentifier(0.4.0.194112.1.2)
    Sequence
        ObjectIdentifier(1.3.6.1.4.1.36203.1.1.2)
        Sequence
            Sequence
                ObjectIdentifier(1.3.6.1.5.5.7.2.1)
                IA5String(https://docs.namirialtsp.com/) 
    Sequence
        ObjectIdentifier(0.4.0.2042.1.2)

                       critical(false) 2.5.29.31 value = Sequence
    Sequence
        Tagged [CONTEXT 0]
            Tagged [CONTEXT 0]
                Tagged [CONTEXT 6] IMPLICIT 
                    DER Octet String[53] 

                       critical(true) KeyUsage: 0x40

X509 Java Cert:  [0]         Version: 3
         SerialNumber: 4112325213882364794
             IssuerDN: C=IT,O=Namirial S.p.A./02046570426,OU=Certification Authority,CN=Namirial CA Firma Qualificata
           Start Date: Mon Dec 19 05:35:00 EST 2022
           Final Date: Wed Dec 17 18:00:00 EST 2025
            SubjectDN: C=IT,SURNAME=VINATTIERI,GIVENNAME=GIACOMO,SERIALNUMBER=TINIT-VNTGCM75A21D612F,CN=VINATTIERI GIACOMO,DN=LOVG2022121631199701
           Public Key: RSA Public Key [64:4c:b7:6e:53:05:e9:0a:11:1e:33:72:e2:06:18:79:84:72:e5:b2],[56:66:d1:a4]
        modulus: 85c771c6e1e1c618a6679396bc64b524f883031cf052bd5fe53304cb311daf432a906f8309c9747662e10a1c9af63e16c5a4a05640cff9817ca7e2a2fdb45a428ffb52b03a26bdead50dc83d3ae4da9cb976cae187d0656230819cdbe4a5916a272acf8e7d01732af70203ec969aa832be87c32f33d4e8ea6e9236e2bbf5e17a4839f6010dbed93bf99c55610a47df52cdba3ecc8e5bd64d267cdc7d604ace88da0d0a7cd5cff9f970a29348af23fcc41fce700bc9300b24dbe831581ffa251560e9c3b65a135a79c4eeba362a61f18e1ae7d12cbb98b0dee8b884eeb765b19df91f92ae3c9f091ca6b16e58aee991e5e2fca7e4dfa373f63acb0d8e8726c3fd
public exponent: 10001

  Signature Algorithm: SHA256WITHRSA
            Signature: 4ab92fb1383eec0242bd4f7e298aa78eb725e4bf
                       156612ab0d614701e40e18afaf06846e0d7aa6ae
                       6b9a49a8896ca198e80ed52f849257549e258008
                       291e057720d1afa5c7e47730e5bf24e488dc154f
                       5ae6850c6d1bfb89ed80eaf96e4681d5f678c370
                       16ac2a802cddafe262da6dab6b77d1311775a763
                       f0d3e509866c65aa6d0548486469e92a66327bc5
                       0ffe0f7c4b2f79e4fc4484c8aa7cbe778b0a7815
                       d049fc0b31d1a70c4f0541d6ca24f8bc4d0272c0
                       b9f863eb1bcc6973cba09f04db73a5ae03a57bd6
                       da44a84a3be4df35a9b0b689f77c9529dbf76f19
                       ce4612fa7d804374b104a4b0f2dddf2f1978fb1a
                       b9658b90ed07f3dca41279ca79460e50
       Extensions: 
                       critical(false) 1.3.6.1.5.5.7.1.1 value = Sequence
    Sequence
        ObjectIdentifier(1.3.6.1.5.5.7.48.2)
        Tagged [CONTEXT 6] IMPLICIT 
            DER Octet String[69] 
    Sequence
        ObjectIdentifier(1.3.6.1.5.5.7.48.1)
        Tagged [CONTEXT 6] IMPLICIT 
            DER Octet String[43] 

                       critical(false) 2.5.29.14 value = DER Octet String[20] 

                       critical(false) 2.5.29.35 value = Sequence
    Tagged [CONTEXT 0] IMPLICIT 
        DER Octet String[20] 

                       critical(false) 1.3.6.1.5.5.7.1.3 value = Sequence
    Sequence
        ObjectIdentifier(0.4.0.1862.1.1)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.3)
        Integer(20)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.4)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.6)
        Sequence
            ObjectIdentifier(0.4.0.1862.1.6.1)
    Sequence
        ObjectIdentifier(0.4.0.1862.1.5)
        Sequence
            Sequence
                IA5String(https://docs.namirialtsp.com/documents/PDS/PDS_en.pdf) 
                PrintableString(en) 
            Sequence
                IA5String(https://docs.namirialtsp.com/documents/PDS/PDS_it.pdf) 
                PrintableString(it) 

                       critical(false) 2.5.29.32 value = Sequence
    Sequence
        ObjectIdentifier(0.4.0.194112.1.2)
    Sequence
        ObjectIdentifier(1.3.6.1.4.1.36203.1.1.2)
        Sequence
            Sequence
                ObjectIdentifier(1.3.6.1.5.5.7.2.1)
                IA5String(https://docs.namirialtsp.com/) 
    Sequence
        ObjectIdentifier(0.4.0.2042.1.2)

                       critical(false) 2.5.29.31 value = Sequence
    Sequence
        Tagged [CONTEXT 0]
            Tagged [CONTEXT 0]
                Tagged [CONTEXT 6] IMPLICIT 
                    DER Octet String[53] 

                       critical(true) KeyUsage: 0x40

X500 Principal: DNQ=LOVG2022121631199701, CN=VINATTIERI GIACOMO, SERIALNUMBER=TINIT-VNTGCM75A21D612F, GIVENNAME=GIACOMO, SURNAME=VINATTIERI, C=IT

but I will admit I'm on the as-of-yet unreleased BC 1.78. However, it doesn't look like this code has changed in a while. I went through PEMParser because I wanted to see what the internal X509CertificateHolder would output, which seems OK, but then went back to DER for the CertificateFactory parsing to get the java.security.cert.X509Certificate from the BC provider.

@ralfhauser
Copy link
Author

bc*-jdk18on-171.jar

@ralfhauser
Copy link
Author

ralfhauser commented Apr 10, 2024

if you add one line to your code, it is reproducible

`...
System.out.println("X500 Principal: " + xPrinc);

X500Name subDN = new X500Name(xPrinc.toString());`

@cipherboy
Copy link
Collaborator

@ralfhauser Have you seen the alternative X500Name constructor?

public X500Name(X500NameStyle style,
                java.lang.String dirName)

This would let you parse DQNs directly in this format:

private static final String dnqSubject = "DNQ=Legion of the Bouncy Castle Inc.";

public static class DNQStyle
extends BCStyle
{
public static final DNQStyle INSTANCE = new DNQStyle();
private DNQStyle()
{
defaultLookUp.put("dnq", BCStyle.DN_QUALIFIER);
defaultSymbols.put(BCStyle.DN_QUALIFIER, "DNQ");
}
}

// basic style test
X500Name dnqName = new X500Name(DNQStyle.INSTANCE, dnqSubject);
isEquals(dnqName.toString(), "DNQ=Legion of the Bouncy Castle Inc.");

If you're willing to modify your application code, I think this will work the best, and follows what was originally intended (w.r.t. custom names for OIDs). Let me know what you think!

@ralfhauser
Copy link
Author

ralfhauser commented Apr 10, 2024

Why can't the simple constructor not handle this ?
Or why is this DNQStyle only in the test class and not in X500Name.java
as

private static X500NameStyle defaultStyle = DNQStyle.INSTANCE; //BCStyle.INSTANCE;

as it extends BCStyle , it seems to backward compatible (except for the IllegalArgumentException probably almost nobody is keen on seeing ?)

@cipherboy
Copy link
Collaborator

@ralfhauser Perhaps @dghgit can weigh in...

My understanding is a style class allows for overriding our understanding/parsing of string attributes into proper RDN sequences. You might prefer DNQ= in the string form, others might prefer dnQualifier=, which the default aligns with the RFC4519 style guide. Others still might want to parse completely custom OIDs (e.g., my favorite 1.2.3.4.5.6.7.8.9 should be parsed as favoriteSport=!). With a broad enough set of OIDs, you're bound to get overlap names to multiple OIDs (see e.g., uid=: is this a 2.5.4.45 or a 0.9.2342.19200300.100.1.1? Probably depends on the context!).

A custom style parser gives you the flexibility to set the string form+identifiers of RDN attributes you want to see/understand/parse (and extending BCStyle should hopefully give you), while letting others set the forms of attributes they want to see, without stepping on too many toes along the way. :-)

My 2c -- but this was likely written for exactly this type of extensibility.

Whether or not we want to add it to the default constructor (and if we'll add it as dnq vs dnqualifier) probably depends on popularity of this attribute. Given existing RFCs state it should be called dnQualifier, I'm guessing its relatively unlikely we'll parse it as dnq, and may be unlikely we'll add dnQualifier either given it exists in the RFC4519Style class... But I will defer to @dghgit here again.

@dghgit
Copy link
Contributor

dghgit commented Apr 14, 2024

Hi @ralfhauser, has been a while since this has come up.

So, the issue is it's not that anyone's right or wrong, and this isn't the first time we've found ourselves and Sun/Oracle using different symbols, IBM for example tend to treat this one as DNQUALIFIER, in our case it's always been "DN" (looking at RFC 4519 I have to admit IBM's probably the closest to correct, although we actually added the attribute before RFC 4519 came out, I'd guess based on either what OpenSSL was using at the time, or what Sun was using at the time, it was around 2005 though so while I was around, I'm afraid what and who in regards to this one are well lost in time).

What I've found in general is that avoiding converting directory names to strings until you actually have to hand one over to a human is the best idea, as the alternative is a path to madness.

The following will allow you to convert the directory name without issue:

    X509Certificate cer = (X509Certificate)certFact.generateCertificate(new FileInputStream("dnq.pem"));
    
    X500Name x500Name = X500Name.getInstance(cer.getSubjectX500Principal().getEncoded());

    System.err.println(x500Name);

Now, it you'd like that to print just as the Oracle one does, there's a choice between using the X500NameStyle class as @cipherboy suggests (which can be useful if you like life with X500Name) or simply doing the reverse at output time, i.e:

   System.err.println(new X500Principal(x500Name.getEncoded()));

It all depends how you want to play it. The one thing you can be confident of whatever decision you make you'll almost certainly run into someone that wants it to be done differently so I would recommend allowing for flexibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants