【问题标题】:How to convert JSON Web Key Set (JWKS) public keys to PEM file using BASH?如何使用 BASH 将 JSON Web 密钥集 (JWKS) 公钥转换为 PEM 文件?
【发布时间】:2020-04-29 13:28:40
【问题描述】:

假设您使用 AWS,并且希望使用 Cognito 使用基于 ID 的身份验证。

然后aws 为您提供一个公钥,您可以使用它来验证 cognito 有效负载。

我们还假设您不想或不能使用任何花哨的库,例如 jose,因为您被锁定在高度受限的环境中。

要走的路是一个 BASH 脚本,它可以使旧的 Brian Kernighan 自豪的。 您必须先了解编码。 Base64Url需要翻译成Base64。

这是使用填充字符= 实现的 如果字符数可以被4 整除,则不需要填充。 这与二进制数字表示有关。 处理好之后,您可以将Base64 翻译成binary

但是如何仅使用 BASH 和 BASH 程序将 JWKS/JWT 转换为 PEM 文件?

【问题讨论】:

  • 您可以忽略 base64 -d 为缺少 = 填充而尖叫,如下所示:<<<'SGVsbG8geW91Cg' base64 -d 2>/dev/null ||:

标签: bash amazon-web-services openssl jwt pem


【解决方案1】:

这是我按照下面列出的官方文档和来源提出的解决方案。

https://aws.amazon.com/premiumsupport/knowledge-center/decode-verify-cognito-json-token/

请调整输入网址或直接使用json token,并确保您已安装jq

在函数中以 cmets 形式提供描述性帮助。

在 2020 年 4 月 28 日在 Ubuntu 18.04 和 AmazonLinux2 (CentOS) 上测试成功

#!/usr/bin/env bash
set -e

# FUNCTIONS
decodeBase64UrlUInt() { #input:base64UrlUnsignedInteger
    local binaryDigits paddedStr
    case $(( ${#1} % 4 )) in
        2) paddedStr="$1=="   ;;
        3) paddedStr="$1="    ;;
        *) paddedStr="$1"     ;;
    esac
    binaryDigits=$(             \
        echo -n "$paddedStr"    \
        | tr '_-' '/+'          \
        | openssl enc -d -a -A  \
        | xxd -b -g 0           \
        | cut -d ' ' -f 2       \
        | paste -s -d ''        \
    )
    echo "ibase=2; obase=A; $binaryDigits" | bc
    # openssl   enc:encoding; -d=decrypt; -a=-base64; -A=singleLineBuffer
    # xxd       "make-hexdump": -b=bits; -g=groupsize
    # cut       -d=delimiter; -f=field
    # paste     -s=serial|singleFile; -d=delimiter
}

base64UrlToHex() { #input:base64UrlString
    local hexStr paddedStr
    case $(( ${#1} % 4 )) in
        2) paddedStr="$1=="   ;;
        3) paddedStr="$1="    ;;
        *) paddedStr="$1"     ;;
    esac
    hexStr=$(                   \
        echo -n "$paddedStr"    \
        | tr '_-' '/+'          \
        | base64 -d             \
        | xxd -p -u             \
        | tr -d '\n'            \
    )
    echo "$hexStr"
    # base64    -d=decode
    # xxd       -p=-plain=continuousHexDump; -u=upperCase
    # tr        -d=delete
}

asn1Conf() { #input:hexStrPlainUpperCase
    local e="$1"
    local n="$2"
    echo "
        asn1 = SEQUENCE:pubkeyinfo
        [pubkeyinfo]
        algorithm = SEQUENCE:rsa_alg
        pubkey = BITWRAP,SEQUENCE:rsapubkey
        [rsa_alg]
        algorithm = OID:rsaEncryption
        parameter = NULL
        [rsapubkey]
        n = INTEGER:0x$n
        e = INTEGER:0x$e
    " | sed '/^$/d ; s/^ *//g'              \
    | openssl asn1parse                     \
        -genconf    /dev/stdin              \
        -out        /dev/stdout             \
    | openssl rsa                           \
        -pubin                              \
            -inform     DER                 \
            -outform    PEM                 \
            -in         /dev/stdin          \
            -out        /dev/
    # sed       /^$/d=removeEmptyLines; /^ */=removeLeadingSpaces
}

main() {
    local e n hexArr
    local jwksUrl="$1"
    local jwkJson=$(curl -sSSL $jwksUrl)
    local kidList=$(jq -r '.keys[].kid' <<< "$jwkJson")
    for keyId in $kidList; do
        n=$(jq -r ".keys[] | select(.kid == \"$keyId\") | .n" <<< "$jwkJson")
        e=$(jq -r ".keys[] | select(.kid == \"$keyId\") | .e" <<< "$jwkJson")
        echo -e "\n$keyId"
        # decodeBase64UrlUInt "$e"
        # decodeBase64UrlUInt "$n"
        asn1Conf $(base64UrlToHex "$e") $(base64UrlToHex "$n")
    done
}

# MAIN
main 'https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json'
exit 0

特别感谢:

尤里·奥帕林 https://www.yuryoparin.com/2014/05/base64url-in-bash.html

塞德里克·德尔泰尔 https://github.com/Moodstocks/moodstocks-api-clients/blob/master/bash/base64url.sh

阿尔维斯·唐 https://gist.github.com/alvis/89007e96f7958f2686036d4276d28e47

【讨论】:

    【解决方案2】:

    这里有一些选项:

    要么忽略base64 -d 抱怨输入被截断:

    <<<'SGVsbG8geW91Cg' base64 -d 2>/dev/null ||:
    

    或者在解码之前用 Bash 修复 base64 填充:

    base64URL='SGVsbG8geW91Cg'
    
    printf -v pad_space '%*s' $((${#base64URL}%4)) ''
    
    padded_base64="$base64URL${pad_space// /=}"
    
    <<<"$padded_base64" base64 -d
    

    【讨论】:

    • URL 和 PEM 文件呢?
    猜你喜欢
    • 2020-07-05
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    相关资源
    最近更新 更多