pdk-jwt-lib 1.10.0

PDK JWT Library
Documentation
// Copyright (c) 2026, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

//! # Elliptic Curve Public Key Parser
//!
//! This module provides parsing functionality for elliptic curve public keys
//! used in ES256 and ES384 JWT signature validation.

use crate::model::pk::PemLike;

#[cfg(not(any(feature = "fips", fips)))]
use crate::error::jwt_error::JWTError;
#[cfg(not(any(feature = "fips", fips)))]
use elliptic_curve::pkcs8::{AssociatedOid, DecodePublicKey};
#[cfg(not(any(feature = "fips", fips)))]
use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
#[cfg(not(any(feature = "fips", fips)))]
use elliptic_curve::{CurveArithmetic, JwkParameters, PublicKey};

#[cfg(not(any(feature = "fips", fips)))]
pub fn parse_es_pk<C>(public_key: String) -> Result<PublicKey<C>, JWTError>
where
    C: CurveArithmetic + JwkParameters + AssociatedOid,
    <C as CurveArithmetic>::AffinePoint: FromEncodedPoint<C>,
    <C as elliptic_curve::Curve>::FieldBytesSize: ModulusSize,
    <C as CurveArithmetic>::AffinePoint: ToEncodedPoint<C>,
{
    match parse_pem(public_key) {
        Ok(pem) => match PublicKey::from_public_key_der(pem.contents()) {
            Ok(pk) => Ok(pk),
            Err(_) => Err(JWTError::EsPublicKeyParseFailed(String::from(
                "Error parsing public key.",
            ))),
        },
        Err(_) => Err(JWTError::EsPublicKeyParseFailed(String::from(
            "Error parsing public key.",
        ))),
    }
}

pub fn parse_pem(mut public_key: String) -> pem::Result<pem::Pem> {
    if public_key.has_ecdsa_header() {
        public_key = public_key.replace(" ECDSA ", " ");
    } else if !public_key.has_pkcs8_header() {
        public_key.complete_to_pkcs8_pem()
    }

    pem::parse(public_key)
}

#[cfg(test)]
#[cfg(not(any(feature = "fips", fips)))]
mod tests {
    use super::parse_es_pk;
    use elliptic_curve::{pkcs8::DecodePublicKey, PublicKey};
    use p256::NistP256;

    const ES_PUBLIC_KEY_PEM_ECDSA: &str = "-----BEGIN ECDSA PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERqVXn+o+6zEOpWEsGw5CsB+wd8zO
jxu0uASGpiGP+wYfcc1unyMxcStbDzUjRuObY8DalaCJ9/J6UrkQkZBtZw==
-----END ECDSA PUBLIC KEY-----";

    const ES_PUBLIC_KEY_PEM_PKCS8_TRANSFORMED: &str = "-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERqVXn+o+6zEOpWEsGw5CsB+wd8zO
jxu0uASGpiGP+wYfcc1unyMxcStbDzUjRuObY8DalaCJ9/J6UrkQkZBtZw==
-----END PUBLIC KEY-----";

    #[test]
    fn should_fail_on_a_bad_formed_public_key_for_es256() {
        let result = parse_es_pk::<NistP256>(String::from("i am not a valid key"));
        assert!(result.is_err());
    }

    #[test]
    fn should_ok_on_ecdsa_header_es_formed_public_key_for_es256() {
        let result = parse_es_pk::<NistP256>(String::from(ES_PUBLIC_KEY_PEM_ECDSA));
        assert!(result.is_ok());

        let expected =
            PublicKey::<NistP256>::from_public_key_pem(ES_PUBLIC_KEY_PEM_PKCS8_TRANSFORMED);

        assert_eq!(result.unwrap(), expected.unwrap());
    }
}