Categorygithub.com/SierraSoftworks/sshsign-go
modulepackage
0.0.0-20240905171849-710d54cb823f
Repository: https://github.com/sierrasoftworks/sshsign-go.git
Documentation: pkg.go.dev

# README

sshsign

Sign data using your SSH key within Go

Cryptographic signatures form a critical part of integrity and provenance for many modern systems. The traditional means for handling this has been X.509 certificates, however these can be complex to manage especially for simple use-cases. Alternatives like PGP/GPG reduce this complexity but offer reduced security (due to their use of outdated cryptographic protocols) and others like signify and minisign are not widely adopted.

Something that is widely adopted is SSH keys, which most folks reading this will be very familiar with. As of OpenSSH 8.0 there is a standardized protocol for using your SSH keys to sign arbitrary files and then verify those signatures, making it easy to leverage a modern, widely adopted, crypto-system for general signature validation. Unfortunately, the Go x/crypto/ssh package doesn't provide support for using this functionality out of the box, hence the introduction of this package.

Features

  • Sign and verify data using SSH keys.
  • Full integration with the x/crypto/ssh library.
  • Fully compatible with ssh-keygen's signing outputs.
  • Simple interface with streaming data support for large files.

Example

package main

import (
    "log"
    "io"
    "io/ioutil"

    "github.com/SierraSoftworks/sshsign-go"
	"golang.org/x/crypto/ssh"
)

func main() {
    armoured := sign("/path/to/file.txt", "/path/to/id_rsa")
    log.Printf("Signature:\n %s\n", string(armoured))

    signedBy := verify("/path/to/file.txt", armoured)
    log.Printf("Signed by: %s\n", signedBy)
}

func sign(file, key string) string {
    privateKeyBytes, err := ioutil.ReadFile(key)
    must(err)
    
    privateKey, err := ssh.ParsePrivateKey(privateKeyBytes)
    must(err)

    file, err := io.Open(file)
    must(err)
    defer f.Close()

    signer := sshsign.DefaultSigner("file", sshsign.SHA512, privateKey)
    sig, err := signer.Sign(file)
    must(err)

    armoured, err := sig.MarshalArmoured()
    must(err)
}

func verify(file, signature string) string {
    sig, err := sshsign.UnmarshalArmoured([]byte(signature))
    must(err)

    file, err := io.Open(file)
    must(err)
    defer f.Close()

    verifier := sshsign.DefaultVerifier("file", sshsign.SHA512)
    must(verifier.Verify(file, sig))

    publicKey, err := sig.PublicKey()
    must(err)
    
    return ssh.FingerprintSHA256(publicKey)
}

func must(err error) {
    if err != nil {
        log.Fatalln(err)
    }
}

References

  1. OpenSSH SSHSIG Protocol Documentation

# Functions

DefaultSigner retrieves the default implementation of the Signer interface for the given namespace and ssh.Signer.
The DefaultVerifier constructs a verifier that can check the validity of an SSH signature.
UnmarshalArmoured consumes an armoured PEM block and returns a Signature, as well as a reference to the remaining data which appears after the signature.
UnmarshalBinary reconstructs a Signature from a binary blob.

# Constants

The magic value used to identify an SSH signature.
The SHA256 hash algorithm may be used to compute a hash for the data that is being signed.
The SHA512 hash algorithm may be used to compute a hash for the data that is being signed.

# Variables

The ErrInvalidHashAlgorithm error is raised when the hash algorithm embedded in the signature does not match the hash algorithm that the verifier is configured to use.
The ErrInvalidNamespace error is raised when the namespace embedded in the signature does not match the namespace that the verifier is configured to use.
The ErrInvalidSignature error is raised when the signature cannot be parsed or does not match the expected signature for the data being validated.
The ErrInvalidSigner error is raised when the signer provided is nil or cannot otherwise be used for signing.
The ErrUnsupportedHashAlgorithm error is raised when the hash algorithm specified either in the signer or in the verifier is not supported by the implementation.
The ErrUnsupportedVersion error is raised when the version embedded in the signature is not supported by the implementation.

# Structs

A Signature is used to attest to the content and origin of a piece of data through cryptographic signing using an SSH key.

# Interfaces

The Signer interface describes something that is able to generate an SSH signature for a given piece of data.
The Verifier interface describes something that is able to verify a piece of data against a given SSH signature.