aboutsummaryrefslogtreecommitdiff
path: root/src/main/ui/MgmtScreen.java
blob: 613aa503bc84953f1656b8b209e7479e3ebe17a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package ui;

import model.asn1.ASN1Object;
import model.asn1.BitString;
import model.asn1.Bool;
import model.asn1.ObjectIdentifier;
import model.asn1.exceptions.ParseException;
import model.asn1.parsing.BytesReader;
import model.csr.CertificationRequest;
import model.pki.SubjectPublicKeyInfo;
import model.pki.cert.Certificate;
import model.pki.cert.Extension;
import model.pki.cert.TbsCertificate;

import java.util.Arrays;
import java.util.Base64;
import java.util.BitSet;

public class MgmtScreen implements UIHandler {
    private final JCA session;

    /**
     * EFFECTS: Init with the parent session.
     */
    public MgmtScreen(JCA session) {
        this.session = session;
    }

    @Override
    public void help() {
        System.out.print("show\tView the public key and CA certificate\n"
                + "csr\tGenerate a CSR for a upper-level CA to sign\n"
                + "install\tInstall a CA certificate\n"
                + "exit\tGo to main menu\n"
                + "help\tPrint this message\n");
    }

    /**
     * EFFECTS: Format the public key and CA
     */
    @Override
    public void show() {
        System.out.printf("Public Key:\t%s\n",
                Base64.getEncoder().encodeToString(session.getCa().getPublicKey().getEncoded()));
        if (!session.checkCA(true)) {
            return;
        }
        final TbsCertificate info = session.getCa().getCertificate().getCertificate();
        System.out.printf("Subject:\t%s\n", info.getSubject().toString());
        System.out.printf("Issuer:\t%s\n", info.getIssuer().toString());
        System.out.printf("Not Before:\t%s\n", info.getValidity().getNotBefore().getTimestamp());
        System.out.printf("Not After:\t%s\n", info.getValidity().getNotAfter().getTimestamp());
        System.out.printf("Signature:\t%s\n",
                Base64.getEncoder().encodeToString(Utils.byteToByte(info.getSubjectPublicKeyInfo()
                        .getSubjectPublicKey().getConvertedVal())));
    }

    private void handleCSR() {
        if (!session.checkCA(false)) {
            return;
        }
        try {
            CertificationRequest req = session.getCa().signCSR();
            System.out.println(Utils.toPEM(req.encodeDER(), "CERTIFICATE REQUEST"));
            session.log("Signed CA CSR.");
        } catch (Throwable e) {
            System.out.println(e.getMessage());
        }
    }

    private void validateCACertificateVersion(Certificate cert) throws ParseException {
        if (cert.getCertificate().getVersion() == null
                || cert.getCertificate().getVersion().getLong() != TbsCertificate.VERSION_V3) {
            throw new ParseException("The input certificate must be V3");
        }
    }

    private void validateCACertificatePublicKey(Certificate cert) throws ParseException {
        final SubjectPublicKeyInfo expectedPKInfo = session.getCa().getCAPublicKeyInfo();
        if (!Arrays.equals(cert.getCertificate().getSubjectPublicKeyInfo().getAlgorithm().getType().getInts(),
                expectedPKInfo.getAlgorithm().getType().getInts())
                || !Arrays.equals(cert.getCertificate().getSubjectPublicKeyInfo().getSubjectPublicKey().getVal(),
                expectedPKInfo.getSubjectPublicKey().getVal())) {
            throw new ParseException("The input certificate does not have the corresponding public key");
        }
    }

    private void validateCACertificateBasicConstraints(Certificate cert) throws ParseException {
        final Extension basicConstraints = cert.getCertificate().getExtension(ObjectIdentifier.OID_BASIC_CONSTRAINTS);
        if (basicConstraints == null
                || basicConstraints.getExtnValue().getBytes().length <= 0) {
            throw new ParseException("The certificate does not have a valid basicConstraints extension.");
        }
        final ASN1Object basicConstraintsValue =
                new ASN1Object(new BytesReader(basicConstraints.getExtnValue().getBytes()), false);
        if (basicConstraintsValue.getLength() <= 0) {
            throw new ParseException("The certificate does not have a valid basicConstraints extension.");
        }
        final ASN1Object bool =
                ASN1Object.parse(new BytesReader(basicConstraintsValue.encodeValueDER()), false);
        if (!(bool instanceof Bool)
                || !((Bool) bool).getValue()) {
            throw new ParseException("The certificate does not have a valid basicConstraints extension.");
        }
    }

    private void validateCACertificateKeyUsage(Certificate cert) throws ParseException {
        final Extension keyUsage = cert.getCertificate().getExtension(ObjectIdentifier.OID_KEY_USAGE);
        if (keyUsage == null
                || keyUsage.getExtnValue().getBytes().length <= 0) {
            throw new ParseException("The certificate does not have a valid keyUsage extension.");
        }
        final ASN1Object keyUsageValue =
                ASN1Object.parse(new BytesReader(keyUsage.getExtnValue().getBytes()), false);
        if (keyUsageValue.getLength() <= 0
                || !(keyUsageValue instanceof BitString)) {
            throw new ParseException("The certificate does not have a valid keyUsage extension.");
        }
        final BitSet bitSet = BitSet.valueOf(Utils.byteToByte(((BitString) keyUsageValue).getVal()));
        if (!bitSet.get(7) || !bitSet.get(2) || !bitSet.get(1)) {
            throw new ParseException("The certificate does not have a valid keyUsage extension.");
        }
    }

    private void handleInstall() {
        if (!session.checkCA(false)) {
            return;
        }
        try {
            final Byte[] in = session.handleInputPEM("CERTIFICATE");
            Certificate cert = new Certificate(new BytesReader(in), false);
            validateCACertificateVersion(cert);
            validateCACertificatePublicKey(cert);
            validateCACertificateBasicConstraints(cert);
            validateCACertificateKeyUsage(cert);
            session.getCa().installCertificate(cert);
            session.log("A CA certificate is installed.");
        } catch (ParseException e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void command(String... args) {
        switch (args[0]) {
            case "csr":
                handleCSR();
                break;
            case "install":
                handleInstall();
                break;
            default:
                help();
                break;
        }
    }

    /**
     * EFFECTS: Go to main menu
     */
    @Override
    public Screen exit() {
        return Screen.MAIN;
    }

    @Override
    public String getPS1() {
        return "/ca/ #";
    }
}