Skip to content

Commit

Permalink
jwt: remove openssl dep
Browse files Browse the repository at this point in the history
  • Loading branch information
andrusha committed Sep 8, 2023
1 parent 13a5494 commit a05c168
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 18 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[workspace]
resolver = "2"
members = [
"jwt",
"snowflake-api"
Expand Down
2 changes: 1 addition & 1 deletion jwt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ license = "Apache-2.0"

[dependencies]
thiserror = "1"
rsa = "0.9"
sha2 = "0.10"
base64 = "0.21"
jsonwebtoken = "8"
openssl = "0.10"
serde = "1"
time = "0.3"

Expand Down
2 changes: 1 addition & 1 deletion jwt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::fs;
use snowflake_jwt;

fn get_token(private_key_path: &str, account_identifier: &str, username: &str) -> Result<String> {
let pem = fs::read(private_key_path)?;
let pem = fs::read_to_string(private_key_path)?;
let full_identifier = format!("{}.{}", account_identifier, username);
let jwt = snowflake_jwt::generate_jwt_token(&pem, &full_identifier)?;

Expand Down
2 changes: 1 addition & 1 deletion jwt/examples/json_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct Args {

fn main() -> Result<()> {
let args = Args::parse();
let pem = fs::read(&args.private_key)?;
let pem = fs::read_to_string(&args.private_key)?;
let full_identifier = format!("{}.{}", &args.account_identifier, &args.username);
let jwt = snowflake_jwt::generate_jwt_token(&pem, &full_identifier)?;

Expand Down
47 changes: 32 additions & 15 deletions jwt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@

use base64::Engine;
use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
use openssl::rsa::Rsa;
use rsa::pkcs1::EncodeRsaPrivateKey;
use rsa::pkcs8::{DecodePrivateKey, EncodePublicKey};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use thiserror::Error;
use time::{Duration, OffsetDateTime};

use crate::JwtError::JwtEncodingError;

#[derive(Error, Debug)]
pub enum JwtError {
#[error(transparent)]
OpenSslError(#[from] openssl::error::ErrorStack),
Rsa(#[from] rsa::Error),

#[error(transparent)]
Pkcs8(#[from] rsa::pkcs8::Error),

#[error(transparent)]
Spki(#[from] rsa::pkcs8::spki::Error),

#[error(transparent)]
Pkcs1(#[from] rsa::pkcs1::Error),

#[error("unable to encode JWT: `{0}`")]
JwtEncodingError(String),
#[error(transparent)]
Utf8(#[from] std::string::FromUtf8Error),

#[error(transparent)]
Der(#[from] rsa::pkcs1::der::Error),

#[error(transparent)]
JwtEncoding(#[from] jsonwebtoken::errors::Error),
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -86,24 +100,27 @@ fn pubkey_fingerprint(pubkey: &[u8]) -> String {
base64::engine::general_purpose::STANDARD.encode(hasher.finalize())
}

pub fn generate_jwt_token<T: AsRef<[u8]>>(
private_key_pem: T,
pub fn generate_jwt_token(
private_key_pem: &str,
// Snowflake expects uppercase <account identifier>.<username>
full_identifier: &str,
) -> Result<String, JwtError> {
// Reading a private key:
// rsa-2048.p8 -> public key -> der bytes -> hash
let privk = Rsa::private_key_from_pem(private_key_pem.as_ref())?;
let pubk = privk.public_key_to_der()?;

let iss = format!("{}.SHA256:{}", full_identifier, pubkey_fingerprint(&pubk));
let pkey = rsa::RsaPrivateKey::from_pkcs8_pem(private_key_pem)?;
let pubk = pkey.to_public_key().to_public_key_der()?;
let iss = format!(
"{}.SHA256:{}",
full_identifier,
pubkey_fingerprint(pubk.as_bytes())
);

let iat = OffsetDateTime::now_utc();
let exp = iat + Duration::days(1);

let claims = Claims::new(iss, full_identifier.to_owned(), iat, exp);
let ek = EncodingKey::from_rsa_der(&privk.private_key_to_der()?);
let ek = EncodingKey::from_rsa_der(pkey.to_pkcs1_der()?.as_bytes());

encode(&Header::new(Algorithm::RS256), &claims, &ek)
.map_err(|e| JwtEncodingError(e.to_string()))
let res = encode(&Header::new(Algorithm::RS256), &claims, &ek)?;
Ok(res)
}

0 comments on commit a05c168

Please sign in to comment.