Skip to content

Commit

Permalink
Merge pull request #39 from depot/certificate-utility
Browse files Browse the repository at this point in the history
Add helpers for `parseCertificate` and `parseCertificateBundle`
  • Loading branch information
jacobwgillespie authored Nov 24, 2023
2 parents e43b0da + 7a6132e commit 2aee70c
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 0 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
},
"dependencies": {
"@grpc/grpc-js": "^1.9.11",
"@peculiar/webcrypto": "^1.4.3",
"@peculiar/x509": "^1.9.5",
"@protobuf-ts/grpc-transport": "^2.9.1",
"@protobuf-ts/runtime": "^2.9.1",
"@protobuf-ts/runtime-rpc": "^2.9.1",
Expand Down
191 changes: 191 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 78 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {ChannelCredentials} from '@grpc/grpc-js'
import {Crypto} from '@peculiar/webcrypto'
import * as x509 from '@peculiar/x509'
import {GrpcTransport} from '@protobuf-ts/grpc-transport'
import {SpiffeWorkloadAPIClient} from './proto/spiffe/workload/workload.client'

Expand All @@ -16,6 +18,82 @@ export function createClient(baseURL?: string) {
return new SpiffeWorkloadAPIClient(transport)
}

/**
* Utility function to parse a raw certificate. Can be used to convert the
* raw certificate into a PEM certificate:
*
* ```typescript
* const cert = parseCertificate(data)
* const pem = cert.toString('pem')
* ```
*
* **Note:** if you have a certificate bundle, use `parseCertificateBundle` instead, as
* this function will incorrectly parse bundles as a single certificate.
*
* @param data The raw data of the certificate
* @returns [X509Certificate](https://peculiarventures.github.io/x509/classes/X509Certificate.html)
* @see https://github.com/PeculiarVentures/x509
*/
export function parseCertificate(data: Uint8Array): x509.X509Certificate {
initCryptoProvider()

return new x509.X509Certificate(data)
}

/**
* Utility function to parse a certificate bundle. Can be used to convert the
* bundle into a PEM chain:
*
* ```typescript
* const certs = parseCertificateBundle(data)
* const pemChain = certs.toString('pem-chain')
* ```
*
* @param data The raw data of the certificate bundle
* @returns [X509Certificates](https://peculiarventures.github.io/x509/classes/X509Certificates.html)
* @see https://github.com/PeculiarVentures/x509
*/
export function parseCertificateBundle(data: Uint8Array): x509.X509Certificates {
initCryptoProvider()

let currentIndex = 0
const certs: x509.X509Certificate[] = []

while (currentIndex < data.length) {
const beginOfSequence = currentIndex

// Skip the first tag byte
currentIndex += 1

// Get the second byte for length value representing bytes
let length = data[currentIndex++]
if (length === 0x80) throw new TypeError('Indefinite length encoding not supported')
if (length & 0x80) {
const lengthBytes = length & 0x7f
length = 0
for (let i = 0; i < lengthBytes; i++) {
length = (length << 8) | data[currentIndex++]
}
}

certs.push(new x509.X509Certificate(data.slice(beginOfSequence, currentIndex + length)))

// Move the current index to the next tag
currentIndex += length
}

return new x509.X509Certificates(certs)
}

function initCryptoProvider() {
try {
x509.cryptoProvider.get()
} catch {
const crypto = new Crypto()
x509.cryptoProvider.set(crypto)
}
}

export * from './proto/google/protobuf/struct'
export * from './proto/spiffe/workload/workload'
export * from './proto/spiffe/workload/workload.client'

0 comments on commit 2aee70c

Please sign in to comment.