COMP 4108 Assignment 3

Public-Key Certificates

Due 11:59PM on 9-Mar-2026

83 marks total


For this assignment, you will work individually.


Unlike previous assignments, there is no submission to Brightspace. Submit your answers to the dedicated assignment submission website. It is only accessible through the Carleton VPN.

Please note that in order to best enforce the course's late policy for this assignment, the latest modification to your submission will dictate your submission time.

Setting up your environment

If you have completed the setup steps for Assignment 1, you will already have created a Linux virtual machine for this course on the SCS OpenStack platform. You will re-purpose that VM instance for this assignment.

Follow the instructions from Assignment 2 to rebuild your VM instance against the comp4108-w26-assignment-03 image. Once you have, connect to it and change your password.

Part A - Introduction (15 Marks)

Relevant textbook sections: 8.1, 8.2, 8.4, 8.5

This assignment illustrates three important aspects of public-key certificates: issuance, usage, and chain validation. We will focus primarily on domain-validated (DV) X.509 certificates, simulating interactions from the perspective of both a web server and a browser (client).

You will first play the role of a web server administrator. Your VM has a certificate file, located at /home/student/root4108.crt, self-signed by our course's certificate authority (CA), 4108 Root CA. In the context of the browser trust model (Model IV in the textbook), this CA's certificate (via its public key) will serve as our only trust anchor. You will request a client certificate from this CA (signed with its private key), for use by your web server in serving content over the TLS protocol. (We will learn more about this protocol in Chapter 9 of the textbook.)

The course's CA loosely follows the ACME protocol (RFC 8555), for domain validation and certificate issuance. ACME aims to standardise and automate all aspects of DV certificate management, and was designed by Let's Encrypt. It can be summarised as follows:

  1. A client creates an account with the ACME server representing the CA.
  2. The client creates an order for a DV certificate, triggering a process by which the CA asks the client to demonstrate control of the domain.
  3. The client fulfills the task, and their account is authorised to manage its domain's certificates with the CA.
  4. The certificate issuance process involves the client submitting a PKCS#10 certificate signing request (CSR) for the authorised domain.

To simulate this protocol for this assignment, you will use a domain that you control. All active SCS accounts have the ability to create a personal homepage directory at people.scs.carleton.ca, and this will be your domain to validate with the course's CA. Once you demonstrate control over your homepage to the CA, the CA can then associate the domain with the public key in your CSR.

Your account with the course's CA (step 1 above) has already been created as part of the assignment submission website, and your credentials should have been sent to you by email. Contact a TA if you are unable to log in.

  1. 1 Mark Create an order (step 2 above) for a DV certificate through Part A of the submission page. Your personal homepage should appear in the Domains table once completed.
    • Note – Your only eligible domain should show as people.scs.carleton.ca/~username, where username is your MyCarletonOne username. Contact a TA if this is not the case.

  2. 8 Marks Complete the validation process (step 3 above) for your domain by clicking the "Not verified" button in the Verification Status column of the Domains table, and then following the request in the displayed dialog to place a verification string on your website. To do this, read the instructions on the SCS Technical Support page for creating a new directory and file on your homepage. Once the file is available, click the "Verify" button at the bottom-right of the dialog. A green "Verified" status should show in the table once completed.
    • Hint – If you are having trouble using your browser to confirm permissions on your new file, try clearing your browser cache.

  3. 6 Marks Use the openssl toolkit on your VM to perform the following steps to create a PKCS#10 CSR and submit it to the course's CA. (The instructions below will guide you on using the toolkit, and see also the information box below to learn more.)
    1. Create a new ED25519 signing key, used for the EdDSA (RFC 8032) elliptic-curve digital signature scheme, with the openssl genpkey command on your VM. (For the related man page, run man openssl-genpkey.) Save this private key as a file named signing.key.
    2. Use the openssl req command to create a new PKCS#10 CSR in PEM format, signing it with your new key. (For the related man page, run man openssl-req.) OpenSSL will generate a corresponding public key from your private key, and embed it into your CSR. The command will also interactively prompt you for standard X.509 certificate fields, and you are free to fill them in as you wish, but your CSR must:
      • Request its Common Name (CN) to be set to your student ID.
      • Have the following X.509v3 extensions defined:
        • A Subject Alternative Name extension, with the HTTP URI of your homepage, e.g. http://people.scs.carleton.ca/~username.
        • A Basic Constraints extension, marked as critical, with cA set to true and pathLenConstraint set to 0.
          • Note – This is required for Part B, which will have you sign your own certificate. The client will itself simulate the role of a subordinate CA in this sense.
        • A Key Usage extension, marked as critical, with the digitalSignature and keyCertSign bits set.
        • Hint – You will not be interactively prompted for X.509v3 extensions, as they are optional. You must instead use the -addext option. Available name=value pairs are documented in the man page for x509v3_config.
      Save the CSR to a file named signing.csr. You can view the attributes for your created CSR by running the openssl req command with the -noout and -text options.
    3. Copy the PEM-formatted text of your CSR file. On Part A of the submission page, click the "Request certificate" button in the Certificate column of the Domains table, then paste the CSR contents into the displayed dialog, and then click the "Request" button at the bottom-right.
    4. A green "Manage certificate" button will show in the table if your CSR was valid. (Otherwise, a red button will show with the word "Invalid", along with a reason in the request dialog.) Clicking the "Manage certificate" button will display your signed certificate in a dialog. Save it to your machine to a file called signing.crt for Part B.
The openssl command is part of the OpenSSL cryptographic toolkit, which is often used to implement the TLS protocol, numerous cryptographic primitives, message encryption and decryption, and public-key certificates. It is widely supported and heavily used for secure communications.
You can open your signed certificate .crt file natively on most operating systems to view its properties. On your VM, you can use the openssl x509 command with the -noout and -text options.
Do not lose the private key of your signing key pair, signing.key. (A file pathname to access this will be needed in Part B.)

Part B - Authenticated Key Establishment (40 Marks)

Relevant textbook sections: 4.1, 4.2, 4.4

This part involves implementing a sample client-server protocol for authenticated key transport and confirmation in Python, to illustrate how your certificate could be used in establishing a secure channel. In this protocol, you are the client requesting a new encrypted session with the server. The server only wishes to interact with clients that it can identify; therefore, using a four-way handshake, you will provide your signed public-key certificate and demonstrate that you have control over the corresponding private key. In response, the server will agree to use its chosen session key when interacting with you.

A successful run of the protocol is conceptualised in the diagram below. Each arrow represents a message from one party to the other, labelled M1 through M4. We define the notation {x}y to mean encrypting x using key y.

  • M1. The client sends their student ID (IDstud) and public key (pk) embedded in their certificate (cert) to initiate the protocol.
  • M2. Through a key encapsulation mechanism (KEM), the server encapsulates a symmetric session key (k) using the client's public key (pk). It then encrypts a random challenge integer (C) using k and a fresh nonce (N1).
  • M3. The client sends (IDstud) once again, along with the result of encrypting C+1 with k and nonce N2. (Both nonces, N1 and N2, are parameters used to initialise the symmetric cipher for which the key k is used.)
  • M4. The server confirms the result of the challenge, indicating whether the session key is verified as confirmed.

Your task is to implement the client side of the above protocol in Python, and to complete one handshake with our course server over HTTP. Since this protocol requires a public key for the KEM, you will generate a new key pair for this. (Your certificate from Part A, signed by the course's CA, holds a public key whose use should be restricted to signing only. Refer to pages 40 and 41 of the textbook for a brief discussion on this topic.) Then, you will use your signing key pair from Part A to self-sign your new public key, creating a certificate chain that the server can validate.

The server has chosen to implement its side of the protocol as follows:

  • The KEM is specified by the Hybrid Public Key Encryption (HPKE) scheme. (If you are interested in more details about this specific KEM, see RFC 9180, under section 7.1.)
  • The AEAD ID chosen for HPKE is ChaCha20Poly1305.
  • The encapsulated session key is to be used for encryption and decryption with the ChaCha20 cipher.

Each message in the handshake will be exchanged as JSON in a POST body, and is documented below, beneath its associated question. To ensure a consistent development experience, we recommend that you use your VM's Python installation to run your client code:

For this assignment, use the pycryptodome package for performing cryptographic operations, and the requests package for making HTTP POST requests in JSON. Install these packages using your VM's included pip3 command.

  1. 5 Marks Use the openssl toolkit on your VM to self-sign a new public-key certificate, to provide the public key that the server will use in the KEM. Then, use the submission website to validate your certificate chain.
    1. Create a new X25519 private key for Elliptic-Curve Diffie-Hellman (ECDH) key exchange, using the openssl genpkey command on your VM. Save this private key as a file named key_encapsulation.key.
    2. Use the openssl req command with the -x509 option to create an X.509 certificate for your new key, using your signing key pair from Part A to sign it as a subordinate CA. OpenSSL will generate a corresponding public key from your X25519 private key, and embed it into the certificate. The command will also interactively prompt you for standard X.509 certificate fields, and you are free to fill them in as you wish, but your certificate must:
      • Have its Common Name set to your student ID.
      • Define the Basic Constraints extension, marked as critical, with cA set to false.
        • Note – Think about the rationale for setting this differently from your CSR for Part A. This might be helpful on a midterm.
      • Define the Key Usage extension, marked as critical, with the keyEncipherment bit set.
      Save the certificate to a file named key_encapsulation.crt.
    3. To verify that your certificate is signed correctly on Part B of the submission page: copy the PEM-formatted text of your certificate file, then paste it into the text box, and then click the "Validate" button. If your certificate could not be validated, a message will show below the text box with a reason.
    If you are unable to complete this question because of an issue validating your certificate chain through the course's CA, you can choose to receive zero marks and skip to the next question. Your certificate chain does not need to validate in order to continue; however, the other requirements (key pair algorithm, X.509 certificate fields) must be met.
  2. 5 Marks Implement a Python client to send the first message in the protocol, M1, to the course server at http://134.117.225.32/get_challenge.php. Documentation on expected attributes for M1 (and the server's response, M2) is available in OpenAPI format within the collapsible section below. You may make as many attempts as you need to receive a successful outcome; only your last attempt will be recorded.

    
    openapi: 3.1.1
    info:
      version: "1"
      title: "Assignment 3 - Part B"
    servers:
      - url: "http://134.117.225.32"
    paths:
      "/get_challenge.php":
        post:
          summary: "Request a new session key and challenge from the server."
          requestBody:
            required: true
            description: "M1: Your student ID and certificate."
            content:
              "application/json":
                schema:
                  type: object
                  properties:
                    "student_id":
                      type: string
                      description: >
                        Your student ID.
                    "certificate":
                      type: string
                      description: >
                        Your PEM-formatted certificate from question 1, certifying your key encapsulation public key.
          responses:
            "201":
              description: "M2: The encrypted challenge and session key."
              content:
                "application/json":
                  schema:
                    type: object
                    properties:
                      "session_key_encapsulated":
                        type: string
                        format: base64
                        description: >
                          The HPKE (RFC 9180) encapsulated ChaCha20 session key, encoded as base64.
                      "challenge_encrypted":
                        type: string
                        format: base64
                        description: >
                          A string containing the challenge integer, encrypted with the session key and nonce, then encoded as base64.
                      "nonce":
                        type: string
                        format: base64
                        description: >
                          The nonce used in encrypting challenge_encrypted, encoded as base64.
    
            "400":
              description: "There is an issue with the request."
              content:
                "application/json":
                  schema:
                    type: object
                    properties:
                      "error_reason":
                        type: string
                        description: "The issue identified."
                      
    • Note – If you are unfamiliar with OpenAPI specifications, you can paste one into an online viewer, like Swagger Editor by SmartBear.

  3. 30 Marks Modify your Python client to send the third message, M3, to the course server at http://134.117.225.32/send_challenge.php. Documentation on expected attributes for M3 (and the server's response, M4) is available in OpenAPI format within the collapsible section below. You may make as many attempts as you need to receive a successful outcome; only your last attempt will be recorded.

    
    openapi: 3.1.1
    info:
      version: "1"
      title: "Assignment 3 - Part B"
    servers:
      - url: "http://134.117.225.32"
    paths:
      "/send_challenge.php":
        post:
          summary: "Respond to an existing challenge to complete the handshake with the server."
          requestBody:
            required: true
            description: "M3: Your student ID, challenge response, and ChaCha20 nonce."
            content:
              "application/json":
                schema:
                  type: object
                  properties:
                    "student_id":
                      type: string
                      description: >
                        Your student ID.
                    "challenge_response_encrypted":
                      type: string
                      format: base64
                      description: >
                        The challenge response integer, C+1, as a string, encrypted using the ChaCha20 session key, and encoded as base64.
                    "nonce":
                      type: string
                      format: base64
                      description: >
                        The nonce used in encrypting challenge_response_encrypted, encoded as base64.
    
          responses:
            "200":
              description: "M4: The result of the handshake."
              content:
                "application/json":
                  schema:
                    type: object
                    properties:
                      "challenge_outcome":
                        type: boolean
                        description: "A flag indicating challenge success or failure."
    
            "400":
              description: "There is an issue with the request."
              content:
                "application/json":
                  schema:
                    type: object
                    properties:
                      "error_reason":
                        type: string
                        description: "The issue identified."
                      
    • Hints
      • Use the Crypto.PublicKey.ECC package to import your private key.
      • To decode a base64-formatted string into bytes, use the b64decode() function from the base64 package. To encode one, call b64encode().decode().
      • To parse a string as an integer, use the built-in int() function. Do not use the decimal package.
      • pycryptodome's HPKE implementation does not yet support the Secret Export functions defined in RFC 9180. Until they are, you can decapsulate the secret key by accessing the _export_secret member of an initialised HPKE_Cipher object.

Part C - Chain Validation (28 Marks)

Relevant textbook sections: 8.1, 8.2, 8.5

This part involves validating public-key certificate chains, similar to how a web browser performs server authentication during a TLS handshake.

In Part C of the submission page, you will find 14 PEM-formatted certificates, each provided to you by a server that claims to be website.com. We will assume again that your only available trust anchor is the course CA's public key. Some certificates are signed by a subsidiary of the course CA, 4108 Intermediate CA—if this is the case, you should incorporate the intermediate certificate on your VM, located at /home/student/intermediate4108.crt, into your verification.

  1. 28 Marks Use the openssl verify command on your VM to determine the validity of each of the 14 provided certificates, within a certificate chain originating from the course's CA certificate. For each certificate you correctly determine to be valid, you will receive 2 marks. If you believe that a certificate fails your validation, you will be prompted with a drop-down menu to further clarify why it failed—in this case, you will receive 1 mark for the correct invalidation, and 1 mark for the correct justification.
In TLS, all server certificates required to establish a valid chain are concatenated, and then sent to the client by the server, as part of one certificate bundle. Therefore, in practice, the onus of constructing a valid trust chain would typically not fall on the browser client—we are only expecting you to do it here for educational reasons.
Only your last submission will be recorded. If you wish to change and re-submit your answers, you can refer to your previously submitted answers on the menu page of the submission website, under the Part C section.