-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(auth): add support for Common Access Cards (#4076)
This includes two new scripts to aid in some common testing operations: checking a card PIN and getting a CAC certificate.
- Loading branch information
1 parent
7022baa
commit f8e32c3
Showing
22 changed files
with
1,045 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env node | ||
|
||
require('esbuild-runner/register'); | ||
require('./cac_get_cert').main(process.argv.slice(2)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { createWriteStream } from 'fs'; | ||
import { throwIllegalValue } from '@votingworks/basics'; | ||
import { CARD_DOD_CERT, CommonAccessCard } from '../src/cac'; | ||
import { waitForReadyCardStatus } from './utils'; | ||
|
||
/** | ||
* Gets the certificate from a Common Access Card. | ||
*/ | ||
export async function main(args: readonly string[]): Promise<void> { | ||
let out: NodeJS.WritableStream = process.stdout; | ||
let format: 'pem' | 'json' = 'pem'; | ||
|
||
for (let i = 0; i < args.length; i += 1) { | ||
const arg = args[i]; | ||
|
||
switch (arg) { | ||
case '-o': | ||
case '--output': { | ||
i += 1; | ||
const outputFilePath = args[i]; | ||
if (!outputFilePath) { | ||
process.stderr.write( | ||
`error: cac-get-cert: missing argument for ${arg}\n` | ||
); | ||
process.exit(1); | ||
} | ||
out = createWriteStream(outputFilePath); | ||
break; | ||
} | ||
|
||
case '--json': { | ||
format = 'json'; | ||
break; | ||
} | ||
|
||
case '--pem': { | ||
format = 'pem'; | ||
break; | ||
} | ||
|
||
case '-h': | ||
case '--help': { | ||
process.stdout.write( | ||
`Usage: ${process.argv[1]} [-o OUTPUT_FILE] [--pem (default)|--json]\n` | ||
); | ||
process.exit(0); | ||
break; | ||
} | ||
|
||
default: { | ||
process.stderr.write(`error: cac-get-cert: unknown argument: ${arg}\n`); | ||
process.exit(1); | ||
} | ||
} | ||
} | ||
|
||
const card = new CommonAccessCard(); | ||
await waitForReadyCardStatus(card); | ||
|
||
switch (format) { | ||
case 'pem': { | ||
const pem = await card.getCertificate({ | ||
objectId: CARD_DOD_CERT.OBJECT_ID, | ||
}); | ||
out.write(pem.toString('utf-8'), () => { | ||
process.exit(0); | ||
}); | ||
break; | ||
} | ||
|
||
case 'json': { | ||
const cardStatus = await card.getCardStatus(); | ||
|
||
if (cardStatus.status !== 'ready') { | ||
process.stderr.write('error: card not ready\n'); | ||
process.exit(1); | ||
} | ||
|
||
out.end(JSON.stringify(cardStatus.cardDetails, undefined, 2), () => { | ||
process.exit(0); | ||
}); | ||
break; | ||
} | ||
|
||
default: { | ||
throwIllegalValue(format); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env node | ||
|
||
require('esbuild-runner/register'); | ||
require('./check_pin').main(process.argv.slice(2)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { createInterface } from 'readline'; | ||
import { JavaCard } from '../src'; | ||
import { CommonAccessCardDetails, CommonAccessCard } from '../src/cac'; | ||
import { CardDetails, PinProtectedCard, StatefulCard } from '../src/card'; | ||
import { waitForReadyCardStatus } from './utils'; | ||
|
||
/** | ||
* Checks whether a PIN is correct. | ||
*/ | ||
export async function main(args: readonly string[]): Promise<void> { | ||
let card: PinProtectedCard & | ||
StatefulCard<CardDetails | CommonAccessCardDetails>; | ||
|
||
for (const arg of args) { | ||
switch (arg) { | ||
case '--vxsuite': { | ||
// default | ||
break; | ||
} | ||
|
||
case '--cac': { | ||
card = new CommonAccessCard(); | ||
break; | ||
} | ||
|
||
case '--help': | ||
case '-h': { | ||
process.stdout.write(`Usage: check-pin [--vxsuite (default)|--cac]\n`); | ||
process.exit(0); | ||
break; | ||
} | ||
|
||
default: { | ||
process.stderr.write(`Unknown argument: ${arg}\n`); | ||
process.exit(1); | ||
} | ||
} | ||
} | ||
|
||
const pin = await new Promise<string>((resolve) => { | ||
createInterface(process.stdin, process.stdout).question( | ||
'Enter PIN: ', | ||
resolve | ||
); | ||
}); | ||
|
||
card ??= new JavaCard(); | ||
console.time('waitForReadyCardStatus'); | ||
await waitForReadyCardStatus(card); | ||
console.timeEnd('waitForReadyCardStatus'); | ||
|
||
console.time('checkPin'); | ||
const result = await card.checkPin(pin); | ||
console.timeEnd('checkPin'); | ||
|
||
console.log(result); | ||
process.exit(result.response === 'correct' ? 0 : 1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# DoD Common Access Card Support | ||
|
||
The DoD Common Access Card (CAC) is a smart card issued by the Department of | ||
Defense (DoD) to civilian employees, military personnel, and contractors. The | ||
CAC is used as a general identification card as well as for authentication to | ||
enable access to DoD computer systems and networks. | ||
|
||
At the moment, `vxsuite` does not use the CAC for authentication. However, the | ||
`rave` repository which is based on `vxsuite` does. Because making changes in | ||
the `auth` library to support CAC results in a lot of merge conflicts when | ||
rebasing `rave`, the CAC support has pushed upstream to this repository. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIE8jCCA9qgAwIBAgICCbcwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMx | ||
GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQL | ||
EwNQS0kxHTAbBgNVBAMTFERPRCBKSVRDIEVNQUlMIENBLTYzMB4XDTIzMDMwMjAw | ||
MDAwMFoXDTI2MDMwMTIzNTk1OVowfTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1Uu | ||
Uy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMQwwCgYDVQQLEwNQS0kxDTALBgNV | ||
BAsTBFVTQUYxKTAnBgNVBAMTIEFJRUxMTy5NSUNIQUVMLkFORFJFVy4xNDA0OTIx | ||
Mjg5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuA7zm0eYH8fEmInf | ||
4FS4FvYJmQeeQOTxQRO3J7e9M7L5PBFvY5pL5/E4dwoj9YBh6BT/FwMRgPhmbr9q | ||
ySQ1eb5dOcxXUrN4tIfKfVSDXkOPtGdqi3mQzBAecX9lEjL/5hAs8FGv0iLgyS5g | ||
MjjnJxBBAgKgALNlfSDcCAho5ppjAMAnBw4tSiVw/X30AOVNhWFs+lf2E3O+b0kD | ||
ITWruOjYB1bEltW/blmfLRz/a4vcQTlRiQZ/OakeYkzxgomeq001fYvVNhm4Kosc | ||
1mRclKgDgVD131xue/HvENXDyygT/p4tjwynOYJMws0p2RCj10UmggID5I3oTYFi | ||
W5/hoQIDAQABo4IBlTCCAZEwHwYDVR0jBBgwFoAUelWI79wGAVbXrwV+Dn69eBHD | ||
7lQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC5uaXQuZGlzYS5taWwvY3Js | ||
L0RPREpJVENFTUFJTENBXzYzLmNybDAOBgNVHQ8BAf8EBAMCBsAwFgYDVR0gBA8w | ||
DTALBglghkgBZQIBCyowHQYDVR0OBBYEFP0cH8uIHxeeHWXOT7DQm1TdVaNhMH4G | ||
CCsGAQUFBwEBBHIwcDA+BggrBgEFBQcwAoYyaHR0cDovL2NybC5uaXQuZGlzYS5t | ||
aWwvc2lnbi9ET0RKSVRDRU1BSUxDQV82My5jZXIwLgYIKwYBBQUHMAGGImh0dHA6 | ||
Ly9vY3NwLm5zbjAucmN2cy5uaXQuZGlzYS5taWwwJQYDVR0RBB4wHIEabWljaGFl | ||
bC5haWVsbG8uMkB1cy5hZi5taWwwGwYDVR0JBBQwEjAQBggrBgEFBQcJBDEEEwJV | ||
UzAfBgNVHSUEGDAWBggrBgEFBQcDBAYKKwYBBAGCNwoDDDANBgkqhkiG9w0BAQsF | ||
AAOCAQEAIhcylGXkPyX0pEWaisa+J1Bm3F7Rhtsq3mKdGsVDblMhTg9VVh9Xivyk | ||
6d5OlAIuq4QaISj4CsETtAgiI+FKo2nn0d+4r9SutaUVFT2y607EIO0bscfUxa0G | ||
O2JI475+6EXvsRA863YeMKShToZRII/vhxiVHLxr1gK+uFxe1hxM+cI2XPhWo4AI | ||
dftzKiEV1gmc+P+tsz7vUE3WKuVuV1HAQ8qiQTCDDO8ghhcFjKltwUv+2bBxuGCQ | ||
VDO7kGlhpjYw/PXdeaAAin17cagItbhHt3G9/v6vemZ021iFyBlsmApo0Cy4pY3a | ||
IMZdMJUe17xDlt5XMaCZIALhjrJxmw== | ||
-----END CERTIFICATE----- |
Oops, something went wrong.