| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- function x509Error(msg, cert) {
- return new Error('SASL channel binding: ' + msg + ' when parsing public certificate ' + cert.toString('base64'))
- }
- function readASN1Length(data, index) {
- let length = data[index++]
- if (length < 0x80) return { length, index }
- const lengthBytes = length & 0x7f
- if (lengthBytes > 4) throw x509Error('bad length', data)
- length = 0
- for (let i = 0; i < lengthBytes; i++) {
- length = (length << 8) | data[index++]
- }
- return { length, index }
- }
- function readASN1OID(data, index) {
- if (data[index++] !== 0x6) throw x509Error('non-OID data', data) // 6 = OID
- const { length: OIDLength, index: indexAfterOIDLength } = readASN1Length(data, index)
- index = indexAfterOIDLength
- const lastIndex = index + OIDLength
- const byte1 = data[index++]
- let oid = ((byte1 / 40) >> 0) + '.' + (byte1 % 40)
- while (index < lastIndex) {
- // loop over numbers in OID
- let value = 0
- while (index < lastIndex) {
- // loop over bytes in number
- const nextByte = data[index++]
- value = (value << 7) | (nextByte & 0x7f)
- if (nextByte < 0x80) break
- }
- oid += '.' + value
- }
- return { oid, index }
- }
- function expectASN1Seq(data, index) {
- if (data[index++] !== 0x30) throw x509Error('non-sequence data', data) // 30 = Sequence
- return readASN1Length(data, index)
- }
- function signatureAlgorithmHashFromCertificate(data, index) {
- // read this thread: https://www.postgresql.org/message-id/17760-b6c61e752ec07060%40postgresql.org
- if (index === undefined) index = 0
- index = expectASN1Seq(data, index).index
- const { length: certInfoLength, index: indexAfterCertInfoLength } = expectASN1Seq(data, index)
- index = indexAfterCertInfoLength + certInfoLength // skip over certificate info
- index = expectASN1Seq(data, index).index // skip over signature length field
- const { oid, index: indexAfterOID } = readASN1OID(data, index)
- switch (oid) {
- // RSA
- case '1.2.840.113549.1.1.4':
- return 'MD5'
- case '1.2.840.113549.1.1.5':
- return 'SHA-1'
- case '1.2.840.113549.1.1.11':
- return 'SHA-256'
- case '1.2.840.113549.1.1.12':
- return 'SHA-384'
- case '1.2.840.113549.1.1.13':
- return 'SHA-512'
- case '1.2.840.113549.1.1.14':
- return 'SHA-224'
- case '1.2.840.113549.1.1.15':
- return 'SHA512-224'
- case '1.2.840.113549.1.1.16':
- return 'SHA512-256'
- // ECDSA
- case '1.2.840.10045.4.1':
- return 'SHA-1'
- case '1.2.840.10045.4.3.1':
- return 'SHA-224'
- case '1.2.840.10045.4.3.2':
- return 'SHA-256'
- case '1.2.840.10045.4.3.3':
- return 'SHA-384'
- case '1.2.840.10045.4.3.4':
- return 'SHA-512'
- // RSASSA-PSS: hash is indicated separately
- case '1.2.840.113549.1.1.10': {
- index = indexAfterOID
- index = expectASN1Seq(data, index).index
- if (data[index++] !== 0xa0) throw x509Error('non-tag data', data) // a0 = constructed tag 0
- index = readASN1Length(data, index).index // skip over tag length field
- index = expectASN1Seq(data, index).index // skip over sequence length field
- const { oid: hashOID } = readASN1OID(data, index)
- switch (hashOID) {
- // standalone hash OIDs
- case '1.2.840.113549.2.5':
- return 'MD5'
- case '1.3.14.3.2.26':
- return 'SHA-1'
- case '2.16.840.1.101.3.4.2.1':
- return 'SHA-256'
- case '2.16.840.1.101.3.4.2.2':
- return 'SHA-384'
- case '2.16.840.1.101.3.4.2.3':
- return 'SHA-512'
- }
- throw x509Error('unknown hash OID ' + hashOID, data)
- }
- // Ed25519 -- see https: return//github.com/openssl/openssl/issues/15477
- case '1.3.101.110':
- case '1.3.101.112': // ph
- return 'SHA-512'
- // Ed448 -- still not in pg 17.2 (if supported, digest would be SHAKE256 x 64 bytes)
- case '1.3.101.111':
- case '1.3.101.113': // ph
- throw x509Error('Ed448 certificate channel binding is not currently supported by Postgres')
- }
- throw x509Error('unknown OID ' + oid, data)
- }
- module.exports = { signatureAlgorithmHashFromCertificate }
|