Skip to content

Commit

Permalink
add elliptic library to import-blacklist (#9302)
Browse files Browse the repository at this point in the history
### Description

Adds elliptic library to ts import blacklist for entire monorepo. This is to prevent vulnerabilities such as the one patched here a3ede34

### Other changes

None

### Tested

NA

### Related issues

NA

### Backwards compatibility

Yes

### Documentation

None
  • Loading branch information
alecps authored and martinvol committed May 13, 2022
1 parent c6852a0 commit a85bcfe
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 31 deletions.
8 changes: 5 additions & 3 deletions packages/celotool/src/lib/generate_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import BigNumber from 'bignumber.js'
import * as bip32 from 'bip32'
import * as bip39 from 'bip39'
import * as bls12377js from 'bls12377js'
import { ec as EC } from 'elliptic'
import fs from 'fs'
import { merge, range, repeat } from 'lodash'
import { tmpdir } from 'os'
Expand All @@ -27,8 +26,6 @@ import { getIndexForLoadTestThread } from './geth'
import { GenesisConfig } from './interfaces/genesis-config'
import { ensure0x, strip0x } from './utils'

const ec = new EC('secp256k1')

export enum AccountType {
VALIDATOR = 0,
LOAD_TESTING_ACCOUNT = 1,
Expand Down Expand Up @@ -134,6 +131,11 @@ export const generateAddress = (mnemonic: string, accountType: AccountType, inde
privateKeyToAddress(generatePrivateKey(mnemonic, accountType, index))

export const privateKeyToPublicKey = (privateKey: string): string => {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const ecPrivateKey = ec.keyFromPrivate(Buffer.from(privateKey, 'hex'))
const ecPublicKey: string = ecPrivateKey.getPublic('hex')
return ecPublicKey.slice(2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ import { trimLeading0x } from '@celo/utils/lib/address'
import { verifySignature } from '@celo/utils/lib/signatureUtils'
import Logger from 'bunyan'
import crypto from 'crypto'
import { ec as EC } from 'elliptic'
import { Request } from 'express'
import { rootLogger } from '..'
import { AuthenticationMethod, ErrorMessage, WarningMessage } from '../interfaces'
import { FULL_NODE_TIMEOUT_IN_MS, RETRY_COUNT, RETRY_DELAY_IN_MS } from './constants'

const ec = new EC('secp256k1')

/*
* Confirms that user is who they say they are and throws error on failure to confirm.
* Authorization header should contain the EC signed body
Expand Down Expand Up @@ -79,6 +76,11 @@ export function verifyDEKSignature(
try {
const msgDigest = crypto.createHash('sha256').update(JSON.stringify(message)).digest('hex')

// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const key = ec.keyFromPublic(trimLeading0x(registeredEncryptionKey), 'hex')
const parsedSig = JSON.parse(messageSignature)
if (key.verify(msgDigest, parsedSig)) {
Expand Down
2 changes: 0 additions & 2 deletions packages/sdk/identity/src/odis/query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Utilities for interacting with the Oblivious Decentralized Identifier Service (ODIS)

import { hexToBuffer } from '@celo/base/lib/address'
import { selectiveRetryAsyncWithBackOff } from '@celo/base/lib/async'
import { ContractKit } from '@celo/contractkit'
Expand Down
10 changes: 6 additions & 4 deletions packages/sdk/utils/src/commentEncryption.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { randomBytes } from 'crypto'
import { ec as EC } from 'elliptic'
import { decryptComment, encryptComment } from './commentEncryption'

const ec = new EC('secp256k1')

describe('Comment Encryption', () => {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const self = ec.keyFromPrivate(randomBytes(32))
const selfPublic = Buffer.from(self.getPublic('hex'), 'hex')
const selfPriv = Buffer.from(self.getPrivate('hex'), 'hex')
Expand Down Expand Up @@ -90,7 +92,7 @@ describe('Comment Encryption', () => {

const newComment = 'regression test on encryption method 👍'
// How comment was encrypted.
// Uses elliptic package
// Uses elliptic package (see note above)
// console.info(
// encryptComment(
// comment,
Expand Down
13 changes: 10 additions & 3 deletions packages/sdk/utils/src/dataEncryptionKey.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { randomBytes } from 'crypto'
import { ec as EC } from 'elliptic'
import { decompressPublicKey, deriveDek } from './dataEncryptionKey'

const ec = new EC('secp256k1')

describe('deriveDek', () => {
it('should produce a the expected keys', async () => {
const mnemonic =
Expand All @@ -16,6 +13,11 @@ describe('deriveDek', () => {

describe('decompressPublicKey', () => {
it('should work with compressed input', () => {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const privateKey = ec.keyFromPrivate(randomBytes(32))
const publicKeyFull = Buffer.from(privateKey.getPublic(false, 'hex'), 'hex')
const publicKeyCompressed = Buffer.from(privateKey.getPublic(true, 'hex'), 'hex')
Expand All @@ -24,6 +26,11 @@ describe('decompressPublicKey', () => {
expect(decompressed).toHaveLength(64)
})
it('should work with long form input', () => {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const privateKey = ec.keyFromPrivate(randomBytes(32))
const publicKeyFull = Buffer.from(privateKey.getPublic(false, 'hex'), 'hex')
const decompressed = decompressPublicKey(publicKeyFull)
Expand Down
13 changes: 10 additions & 3 deletions packages/sdk/utils/src/dataEncryptionKey.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { ec as EC } from 'elliptic'
import { Bip39, generateKeys } from './account'
import { ensureLeading0x } from './address'

const ec = new EC('secp256k1')

/**
* Turns a private key to a compressed public key (hex string with hex leader).
*
* @param {Buffer} privateKey Private key.
* @returns {string} Corresponding compessed public key in hex encoding with '0x' leader.
*/
export function compressedPubKey(privateKey: Buffer): string {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const key = ec.keyFromPrivate(privateKey)
return ensureLeading0x(key.getPublic(true, 'hex'))
}
Expand All @@ -23,6 +25,11 @@ export function compressedPubKey(privateKey: Buffer): string {
* @returns Decompresssed public key without prefix.
*/
export function decompressPublicKey(publicKey: Buffer): Buffer {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
return Buffer.from(ec.keyFromPublic(publicKey).getPublic(false, 'hex'), 'hex').slice(1)
}

Expand Down
17 changes: 12 additions & 5 deletions packages/sdk/utils/src/ecdh.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { trimLeading0x } from '@celo/base/lib/address'
import { createECDH } from 'crypto'
import { ec as EC } from 'elliptic'

const secp256k1 = new EC('secp256k1')

export function computeSharedSecret(privateKey: string, publicKey: string): Buffer {
const ecdh = createECDH('secp256k1')
Expand All @@ -19,12 +16,22 @@ export function isCompressed(publicKey: string) {
}

export function ensureCompressed(publicKey: string): string {
return secp256k1.keyFromPublic(ensureUncompressedPrefix(publicKey), 'hex').getPublic(true, 'hex')
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
return ec.keyFromPublic(ensureUncompressedPrefix(publicKey), 'hex').getPublic(true, 'hex')
}

export function ensureUncompressed(publicKey: string) {
const noLeading0x = trimLeading0x(publicKey)
const uncompressed = secp256k1
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const uncompressed = ec
.keyFromPublic(ensureUncompressedPrefix(noLeading0x), 'hex')
.getPublic(false, 'hex')
return uncompressed
Expand Down
13 changes: 11 additions & 2 deletions packages/sdk/utils/src/ecies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
'use strict'

import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto'
import { ec as EC } from 'elliptic'
const ec = new EC('secp256k1')

export const IV_LENGTH = 16

Expand Down Expand Up @@ -134,6 +132,11 @@ export function AES128DecryptAndHMAC(
* @returns {Buffer} Encrypted message, serialized, 113+ bytes
*/
export function Encrypt(pubKeyTo: Buffer, plaintext: Buffer) {
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const ephemPrivKey = ec.keyFromPrivate(randomBytes(32))
const ephemPubKey = ephemPrivKey.getPublic(false, 'hex')
const ephemPubKeyEncoded = Buffer.from(ephemPubKey, 'hex')
Expand Down Expand Up @@ -162,6 +165,12 @@ export function Decrypt(privKey: Buffer, encrypted: Buffer) {
const ephemPubKeyEncoded = encrypted.slice(0, 65)
const symmetricEncrypted = encrypted.slice(65)

// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')

const ephemPubKey = ec.keyFromPublic(ephemPubKeyEncoded).getPublic()
const px = ec.keyFromPrivate(privKey).derive(ephemPubKey)
const hash = ConcatKDF(px.toBuffer(), 32)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { verifySignature } from '@celo/utils/lib/signatureUtils'
import { recoverTransaction, verifyEIP712TypedDataSigner } from '@celo/wallet-base'
import { asn1FromPublicKey } from '@celo/wallet-hsm'
import { BigNumber } from 'bignumber.js'
import { ec as EC } from 'elliptic'
import * as ethUtil from 'ethereumjs-util'
import Web3 from 'web3'
import { AwsHsmWallet } from './aws-hsm-wallet'
Expand Down Expand Up @@ -69,7 +68,6 @@ const MOCK_KEY_ID = '1d6db902-9a45-4dd5-bd1e-7250b2306f18'
const AWS_HSM_KEY_ID = USING_MOCK ? MOCK_KEY_ID : process.env.AWS_HSM_KEY_ID

const key1 = PRIVATE_KEY1
const ec = new EC('secp256k1')

const keys: Map<string, string> = new Map([[MOCK_KEY_ID, key1]])
const listKeysResponse = {
Expand Down Expand Up @@ -131,6 +129,11 @@ describe('AwsHsmWallet class', () => {
const privateKey = trimLeading0x(keys.get(KeyId)!)
if (privateKey) {
const pkBuffer = Buffer.from(privateKey, 'hex')
// NOTE: elliptic is disabled elsewhere in this library to prevent
// accidental signing of truncated messages.
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const ec = new EC('secp256k1')
const signature = ec.sign(Message, pkBuffer, { canonical: true })
return { Signature: Buffer.from(signature.toDER()) }
}
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk/wallets/wallet-hsm/src/signature-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Address, ensureLeading0x } from '@celo/base/lib/address'
import { BigNumber } from 'bignumber.js'
import { ec as EC } from 'elliptic'
import * as ethUtil from 'ethereumjs-util'
import { ecdsaRecover } from 'secp256k1'

Expand All @@ -10,15 +9,16 @@ export const publicKeyPrefix: number = 0x04
export const sixtyFour: number = 64
export const thirtyTwo: number = 32

const secp256k1Curve = new EC('secp256k1')

/**
* If the signature is in the "bottom" of the curve, it is non-canonical
* Non-canonical signatures are illegal in Ethereum and therefore the S value
* must be transposed to the lower intersection
* https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures
*/
export const makeCanonical = (S: BigNumber): BigNumber => {
// tslint:disable-next-line:import-blacklist
const EC = require('elliptic').ec
const secp256k1Curve = new EC('secp256k1')
const curveN = bufferToBigNumber(secp256k1Curve.curve.n)
const isCanonical = S.comparedTo(curveN.dividedBy(2)) <= 0
if (!isCanonical) {
Expand Down
3 changes: 2 additions & 1 deletion packages/typescript/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"void-zero": false,
"no-global-arrow-functions": true,
"no-floating-promises": true,
"no-promise-as-boolean": true
"no-promise-as-boolean": true,
"import-blacklist": [true, { "elliptic": ["ec"]}]
}
}

0 comments on commit a85bcfe

Please sign in to comment.