001/*
002 * acme4j - Java ACME client
003 *
004 * Copyright (C) 2018 Richard "Shred" Körber
005 *   http://acme4j.shredzone.org
006 *
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
013 */
014package org.shredzone.acme4j.challenge;
015
016import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
017import static org.assertj.core.api.Assertions.assertThat;
018import static org.assertj.core.api.Assertions.assertThatNoException;
019import static org.shredzone.acme4j.toolbox.TestUtils.getJSON;
020
021import java.security.cert.CertificateParsingException;
022
023import org.junit.jupiter.api.Test;
024import org.shredzone.acme4j.Identifier;
025import org.shredzone.acme4j.Login;
026import org.shredzone.acme4j.Status;
027import org.shredzone.acme4j.toolbox.AcmeUtils;
028import org.shredzone.acme4j.toolbox.JSONBuilder;
029import org.shredzone.acme4j.toolbox.TestUtils;
030import org.shredzone.acme4j.util.KeyPairUtils;
031
032/**
033 * Unit tests for {@link TlsAlpn01ChallengeTest}.
034 */
035public class TlsAlpn01ChallengeTest {
036    private static final String TOKEN =
037            "rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ";
038    private static final String KEY_AUTHORIZATION =
039            "rSoI9JpyvFi-ltdnBW0W1DjKstzG7cHixjzcOjwzAEQ.HnWjTDnyqlCrm6tZ-6wX-TrEXgRdeNu9G71gqxSO6o0";
040
041    private final Login login = TestUtils.login();
042
043    /**
044     * Test that {@link TlsAlpn01Challenge} generates a correct authorization key.
045     */
046    @Test
047    public void testTlsAlpn01Challenge() {
048        var challenge = new TlsAlpn01Challenge(login, getJSON("tlsAlpnChallenge"));
049
050        assertThat(challenge.getType()).isEqualTo(TlsAlpn01Challenge.TYPE);
051        assertThat(challenge.getStatus()).isEqualTo(Status.PENDING);
052        assertThat(challenge.getToken()).isEqualTo(TOKEN);
053        assertThat(challenge.getAuthorization()).isEqualTo(KEY_AUTHORIZATION);
054        assertThat(challenge.getAcmeValidation()).isEqualTo(AcmeUtils.sha256hash(KEY_AUTHORIZATION));
055
056        var response = new JSONBuilder();
057        challenge.prepareResponse(response);
058
059        assertThatJson(response.toString()).isEqualTo("{}");
060    }
061
062    /**
063     * Test that {@link TlsAlpn01Challenge} generates a correct test certificate
064     */
065    @Test
066    public void testTlsAlpn01Certificate() throws CertificateParsingException {
067        var challenge = new TlsAlpn01Challenge(login, getJSON("tlsAlpnChallenge"));
068        var keypair = KeyPairUtils.createKeyPair(2048);
069        var subject = Identifier.dns("example.com");
070
071        var certificate = challenge.createCertificate(keypair, subject);
072
073        // Only check the main requirements. Cert generation is fully tested in CertificateUtilsTest.
074        assertThat(certificate).isNotNull();
075        assertThat(certificate.getSubjectX500Principal().getName()).isEqualTo("CN=acme.invalid");
076        assertThat(certificate.getSubjectAlternativeNames().stream()
077                .map(l -> l.get(1))
078                .map(Object::toString)).contains(subject.getDomain());
079        assertThat(certificate.getCriticalExtensionOIDs()).contains(TlsAlpn01Challenge.ACME_VALIDATION_OID);
080        assertThatNoException().isThrownBy(() -> certificate.verify(keypair.getPublic()));
081    }
082
083}