summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src/helpers/getCertificateInfo.ts
blob: b6f6f98fa4604701c8aae4bbde1f79682a98ff88 (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
import { AsnParser, BasicConstraints, Certificate, id_ce_basicConstraints } from '../deps.ts';

export type CertificateInfo = {
  issuer: Issuer;
  subject: Subject;
  version: number;
  basicConstraintsCA: boolean;
  notBefore: Date;
  notAfter: Date;
  parsedCertificate: Certificate;
};

type Issuer = {
  C?: string;
  O?: string;
  OU?: string;
  CN?: string;
  combined: string;
};

type Subject = {
  C?: string;
  O?: string;
  OU?: string;
  CN?: string;
  combined: string;
};

const issuerSubjectIDKey: { [key: string]: 'C' | 'O' | 'OU' | 'CN' } = {
  '2.5.4.6': 'C',
  '2.5.4.10': 'O',
  '2.5.4.11': 'OU',
  '2.5.4.3': 'CN',
};

/**
 * Extract PEM certificate info
 *
 * @param pemCertificate Result from call to `convertASN1toPEM(x5c[0])`
 */
export function getCertificateInfo(
  leafCertBuffer: Uint8Array,
): CertificateInfo {
  const x509 = AsnParser.parse(leafCertBuffer, Certificate);
  const parsedCert = x509.tbsCertificate;

  // Issuer
  const issuer: Issuer = { combined: '' };
  parsedCert.issuer.forEach(([iss]) => {
    const key = issuerSubjectIDKey[iss.type];
    if (key) {
      issuer[key] = iss.value.toString();
    }
  });
  issuer.combined = issuerSubjectToString(issuer);

  // Subject
  const subject: Subject = { combined: '' };
  parsedCert.subject.forEach(([iss]) => {
    const key = issuerSubjectIDKey[iss.type];
    if (key) {
      subject[key] = iss.value.toString();
    }
  });
  subject.combined = issuerSubjectToString(subject);

  let basicConstraintsCA = false;
  if (parsedCert.extensions) {
    // console.log(parsedCert.extensions);
    for (const ext of parsedCert.extensions) {
      if (ext.extnID === id_ce_basicConstraints) {
        const basicConstraints = AsnParser.parse(
          ext.extnValue,
          BasicConstraints,
        );
        basicConstraintsCA = basicConstraints.cA;
      }
    }
  }

  return {
    issuer,
    subject,
    version: parsedCert.version,
    basicConstraintsCA,
    notBefore: parsedCert.validity.notBefore.getTime(),
    notAfter: parsedCert.validity.notAfter.getTime(),
    parsedCertificate: x509,
  };
}

/**
 * Stringify the parts of Issuer or Subject info for easier comparison of subject issuers with
 * issuer subjects.
 *
 * The order might seem arbitrary, because it is. It should be enough that the two are stringified
 * in the same order.
 */
function issuerSubjectToString(input: Issuer | Subject): string {
  const parts: string[] = [];

  if (input.C) {
    parts.push(input.C);
  }

  if (input.O) {
    parts.push(input.O);
  }

  if (input.OU) {
    parts.push(input.OU);
  }

  if (input.CN) {
    parts.push(input.CN);
  }

  return parts.join(' : ');
}