Skip to content

Instantly share code, notes, and snippets.

@bobcallaway
Created September 3, 2022 14:12

Revisions

  1. bobcallaway created this gist Sep 3, 2022.
    82 changes: 82 additions & 0 deletions openssf eu 2022 demo
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    # used in OpenSSF EU 22 presentation:

    #!/bin/sh
    #set -X
    #doitlive commentecho: true

    ### start second demo

    #!/bin/sh
    #set -x
    #doitlive commentecho: true

    # Requires yubico-piv-tool, step (https://github.com/smallstep/cli), jq, curl

    ## SETUP
    # reset yubikey to factory defaults
    ykman piv reset
    ykman piv keys generate --algorithm ECCP256 9c pubkey.pem

    # generate a sBOM* (silly bill of materials)
    echo "insert dad joke here" > /tmp/sBOM

    # let's sign the sBOM
    yubico-piv-tool -a verify-pin --sign -s 9c -H SHA256 -A ECCP256 -i /tmp/sBOM -o /tmp/sBOM.sig

    # let's upload the information to rekor
    ~/go/bin/rekor-cli upload --pki-format=x509 --artifact /tmp/sBOM --public-key pubkey.pem --signature /tmp/sBOM.sig

    ## FULCIO
    # use step to get ID token from Fulcio OIDC IdP (note this token only lasts 60 sec - TYPE QUICKLY!)
    ~/go/bin/step oauth --provider=https://oauth2.sigstore.dev/auth --client-id=sigstore --listen localhost:0 --oidc --bare 2>/dev/null > id_token

    # extract email from ID token
    ~/go/bin/step crypto jwt inspect --insecure < id_token |jq -r .payload.email | tr -d '\n' > /tmp/email

    # sign email address from inside OIDC token with yubikey
    yubico-piv-tool -a verify-pin --sign -s 9c -H SHA256 -A ECCP256 -i /tmp/email -o /tmp/email.sig
    base64 /tmp/email.sig |tr -d '\n' > /tmp/email.sigb64

    # submit to fulcio via curl (need to sign email address with private key)
    curl -s https://fulcio.sigstore.dev/api/v1/signingCert -H "Authorization: Bearer $(cat id_token)" -H "Accept: application/pem-certificate-chain" -H "Content-Type: application/json" -o signingCertChain.pem --data-binary "{ \"publicKey\": { \"algorithm\": \"ecdsa\", \"content\": \"$(base64 pubkey.pem | tr -d '\n')\" }, \"signedEmailAddress\": \"$(base64 /tmp/email.sig|tr -d '\n')\" }"

    # inspect OIDC ID token
    step crypto jwt inspect --insecure < id_token | egrep -v "sub|user_id"

    # inspect signing cert chain
    openssl crl2pkcs7 -nocrl -certfile signingCertChain.pem | openssl pkcs7 -print_certs -text -noout

    # verify signed email address using pub key in signing cert
    openssl x509 -pubkey -noout -in signingCertChain.pem > signingPubKey.pem
    openssl dgst -sha256 -verify signingPubKey.pem -signature email.sig email
    diff signingPubKey.pem ec_public.pem || echo "pub key from signing cert does not match generated one"

    ## COSIGN or SWISS-ARMY-KNIFE TOOL
    # generate & sign artifact and generate detached signature
    head -c 128 < /dev/urandom > artifact
    openssl dgst -sha256 -sign ec_private.pem artifact > artifact.sig
    openssl dgst -sha256 -verify signingPubKey.pem -signature artifact.sig artifact

    # generate timestamp request
    openssl ts -query -data artifact.sig -cert -sha256 -no_nonce -out request.tsq
    # send to Rekor Timestamping authority to make entry into log for this signature
    # -- note that the index for the timestamp entry in the log is returned as a response HTTP header
    curl -sSH "Content-Type: application/timestamp-query" --data-binary @request.tsq https://rekor.sigstore.dev/api/v1/timestamp -o response.tsr
    # fetch timestamping certificate chain for verification
    curl -sSo ts_chain.pem https://rekor.sigstore.dev/api/v1/timestamp/certchain
    # verify timestamp response
    openssl ts -verify -in response.tsr -queryfile request.tsq -CAfile ts_chain.pem
    # ensure timestamp is during validity period of code signing certificate
    openssl ts -reply -in response.tsr -text | grep "Time stamp"; openssl crl2pkcs7 -nocrl -certfile signingCertChain.pem | openssl pkcs7 -print_certs -text -noout|grep -A2 -m1 Validity

    ## REKOR
    # submit signature for & signing cert to rekor
    curl -s https://rekor.sigstore.dev/api/v1/log/entries -H "Accept: application/json" -H "Content-Type: application/json" -o rekor_output --data-binary " { \"apiVersion\": \"0.0.1\", \"kind\": \"rekord\", \"spec\": { \"signature\": { \"format\": \"x509\", \"content\": \"$(base64 -w0 artifact.sig)\", \"publicKey\": { \"content\": \"$(base64 -w0 signingCertChain.pem)\" } }, \"data\": { \"content\": \"$(base64 -w0 artifact)\" } } }"
    jq '.[keys[0]].body |= (@base64d|fromjson)' rekor_output

    # print inclusion proof for entry
    # curl -s -H "Accept: application/json" https://rekor.sigstore.dev/api/v1/log/entries/$(jq -r -c 'keys[0]' rekor_output) | jq .
    rekor-cli verify --artifact artifact --signature artifact.sig --public-key signingCertChain.pem --pki-format x509

    # delete private key - since all we need to verify signature is stored in Rekor
    rm -rf ec_private.pem