v1.8.0, sign-jwt works
This commit is contained in:
@@ -6,10 +6,10 @@ use jwt::{AlgorithmType, Header, ToBase64};
|
||||
use jwt::header::HeaderType;
|
||||
use rust_util::{util_msg, XResult};
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
use yubikey::{Certificate, YubiKey};
|
||||
use yubikey::piv::{AlgorithmId, sign_data};
|
||||
use yubikey::YubiKey;
|
||||
|
||||
use crate::{digest, pivutil, util};
|
||||
use crate::{digest, pivutil, rsautil, util};
|
||||
|
||||
const SEPARATOR: &str = ".";
|
||||
|
||||
@@ -39,7 +39,7 @@ impl Command for CommandImpl {
|
||||
sub_arg_matches.value_of("slot"), "--slot must assigned, e.g. 82, 83 ... 95, 9a, 9c, 9d, 9e");
|
||||
|
||||
let key_id = sub_arg_matches.value_of("key-id");
|
||||
let claims = opt_value_result!(sub_arg_matches.values_of("claims"), "Claims is required.");
|
||||
let claims = sub_arg_matches.values_of("claims");
|
||||
let payload = sub_arg_matches.value_of("payload");
|
||||
|
||||
let header = Header {
|
||||
@@ -48,16 +48,20 @@ impl Command for CommandImpl {
|
||||
..Default::default()
|
||||
};
|
||||
let mut jwt_claims = BTreeMap::new();
|
||||
if payload.is_none() {
|
||||
for claim in claims {
|
||||
match split_claim(claim) {
|
||||
None => { warning!("Claim '{}' do not contains ':'", claim); }
|
||||
Some((k, v)) => { jwt_claims.insert(k, v); }
|
||||
match (payload, claims) {
|
||||
(Some(_), _) => {}
|
||||
(_, Some(claims)) => {
|
||||
for claim in claims {
|
||||
match split_claim(claim) {
|
||||
None => { warning!("Claim '{}' do not contains ':'", claim); }
|
||||
Some((k, v)) => { jwt_claims.insert(k, v); }
|
||||
}
|
||||
}
|
||||
if !jwt_claims.contains_key("sub") {
|
||||
return simple_error!("Claim sub is not assigned.");
|
||||
}
|
||||
}
|
||||
if !jwt_claims.contains_key("sub") {
|
||||
return simple_error!("Claim sub is not assigned.");
|
||||
}
|
||||
_ => return simple_error!("Payload or Claims is required."),
|
||||
}
|
||||
|
||||
let token_string = sign_jwt(slot, &pin_opt, header, &payload, &jwt_claims)?;
|
||||
@@ -82,8 +86,18 @@ fn sign_jwt(slot: &str, pin_opt: &Option<&str>, mut header: Header, payload: &Op
|
||||
opt_result!(yk.verify_pin(pin.as_bytes()), "YubiKey verify pin failed: {}");
|
||||
}
|
||||
|
||||
// TODO set algorithm
|
||||
let (jwt_algorithm, yk_algorithm) = (AlgorithmType::Es256, AlgorithmId::EccP256);
|
||||
let cert = match Certificate::read(&mut yk, slot_id) {
|
||||
Ok(c) => c,
|
||||
Err(e) => return simple_error!("Read YubiKey certificate failed: {}", e),
|
||||
};
|
||||
let piv_algorithm_id = pivutil::get_algorithm_id(&cert.cert.tbs_certificate.subject_public_key_info)?;
|
||||
|
||||
let (jwt_algorithm, yk_algorithm) = match piv_algorithm_id {
|
||||
AlgorithmId::Rsa1024 => return simple_error!("RSA 1024 bits not supported."),
|
||||
AlgorithmId::Rsa2048 => (AlgorithmType::Rs256, AlgorithmId::Rsa2048),
|
||||
AlgorithmId::EccP256 => (AlgorithmType::Es256, AlgorithmId::EccP256),
|
||||
AlgorithmId::EccP384 => (AlgorithmType::Es384, AlgorithmId::EccP384),
|
||||
};
|
||||
|
||||
header.algorithm = jwt_algorithm;
|
||||
debugging!("Header: {:?}", header);
|
||||
@@ -91,7 +105,7 @@ fn sign_jwt(slot: &str, pin_opt: &Option<&str>, mut header: Header, payload: &Op
|
||||
|
||||
let header = opt_result!(header.to_base64(), "Header to base64 failed: {}");
|
||||
let claims = match payload {
|
||||
Some(payload) => Cow::Owned(payload.to_string()),
|
||||
Some(payload) => Cow::Owned(util::base64_encode_url_safe_no_pad(payload.as_bytes())),
|
||||
None => opt_result!(claims.to_base64(), "Claims to base64 failed: {}"),
|
||||
};
|
||||
|
||||
@@ -99,10 +113,15 @@ fn sign_jwt(slot: &str, pin_opt: &Option<&str>, mut header: Header, payload: &Op
|
||||
tobe_signed.extend_from_slice(header.as_bytes());
|
||||
tobe_signed.extend_from_slice(SEPARATOR.as_bytes());
|
||||
tobe_signed.extend_from_slice(claims.as_bytes());
|
||||
let sha256 = digest::sha256_bytes(&tobe_signed);
|
||||
let raw_in = match jwt_algorithm {
|
||||
AlgorithmType::Rs256 => rsautil::pkcs15_rsa_2048_sign_padding(&digest::sha256_bytes(&tobe_signed)),
|
||||
AlgorithmType::Es256 => digest::sha256_bytes(&tobe_signed),
|
||||
AlgorithmType::Es384 => digest::sha384_bytes(&tobe_signed),
|
||||
_ => return simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm),
|
||||
};
|
||||
|
||||
let signed_data = opt_result!(
|
||||
sign_data(&mut yk, &sha256, yk_algorithm, slot_id), "Sign YubiKey failed: {}");
|
||||
sign_data(&mut yk, &raw_in, yk_algorithm, slot_id), "Sign YubiKey failed: {}");
|
||||
|
||||
let signature = util::base64_encode_url_safe_no_pad(signed_data);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user