Documentation ¶
Overview ¶
Package su3 implements reading the SU3 file format.
SU3 files provide content that is signed by a known identity. They are used to distribute many types of data, including reseed files, plugins, blocklists, and more.
See: https://geti2p.net/spec/updates#su3-file-specification
The Read() function takes an io.Reader, and it returns a *SU3. The *SU3 contains the SU3 file metadata, such as the type of the content and the signer ID. In order to get the file contents, one must pass in the public key associated with the file's signer, so that the signature can be validated. The content can still be read without passing in the key, but after returning the full content the error ErrInvalidSignature will be returned.
Example usage:
// Let's say we are reading an SU3 file from an HTTP body, which is an io.Reader. su3File, err := su3.Read(body) if err != nil { // Handle error. } // Look up this signer's key. key := somehow_lookup_the_key(su3File.SignerID) // Read the content. contentReader := su3File.Content(key) bytes, err := ioutil.ReadAll(contentReader) if errors.Is(err, su3.ErrInvalidSignature) { // The signature is invalid, OR a nil key was provided. } else if err != nil { // Handle error. }
If you want to parse from a []byte, you can wrap it like this:
mySU3FileBytes := []byte{0x00, 0x01, 0x02, 0x03} su3File, err := su3.Read(bytes.NewReader(mySU3FileBytes))
One of the advantages of this library's design is that you can avoid buffering the file contents in memory. Here's how you would stream from an HTTP body directly to disk:
su3File, err := su3.Read(body) if err != nil { // Handle error. } // Look up this signer's key. key := somehow_lookup_the_key(su3File.SignerID) // Stream directly to disk. f, err := os.Create("my_file.txt") if err != nil { // Handle error. } _, err := io.Copy(f, su3File.Content(key)) if errors.Is(err, su3.ErrInvalidSignature) { // The signature is invalid, OR a nil key was provided. // Don't trust the file, delete it! } else if err != nil { // Handle error. }
Note: if you want to read the content, the Content() io.Reader must be read *before* the Signature() io.Reader. If you read the signature first, the content bytes will be thrown away. If you then attempt to read the content, you will get an error. For clarification, see TestReadSignatureFirst.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidPublicKey = errors.New("invalid public key")
var ErrInvalidSignature = errors.New("invalid signature")
var ErrMissingContent = errors.New("missing content")
var ErrMissingContentLength = errors.New("missing content length")
var ErrMissingContentType = errors.New("missing or invalid content type")
var ErrMissingFileFormatVersion = errors.New("missing or incorrect file format version")
var ErrMissingFileType = errors.New("missing or invalid file type")
var ErrMissingMagicBytes = errors.New("missing magic bytes")
var ErrMissingSignature = errors.New("missing signature")
var ErrMissingSignatureLength = errors.New("missing signature length")
var ErrMissingSignatureType = errors.New("missing or invalid signature type")
var ErrMissingSignerID = errors.New("missing signer ID")
var ErrMissingSignerIDLength = errors.New("missing signer ID length")
var ErrMissingUnusedByte12 = errors.New("missing unused byte 12")
var ErrMissingUnusedByte14 = errors.New("missing unused byte 14")
var ErrMissingUnusedByte24 = errors.New("missing unused byte 24")
var ErrMissingUnusedByte26 = errors.New("missing unused byte 26")
var ErrMissingUnusedByte6 = errors.New("missing unused byte 6")
var ErrMissingUnusedBytes28To39 = errors.New("missing unused bytes 28-39")
var ErrMissingVersion = errors.New("missing version")
var ErrMissingVersionLength = errors.New("missing version length")
var ErrUnsupportedSignatureType = errors.New("unsupported signature type")
var ErrVersionTooShort = errors.New("version length too short")
Functions ¶
This section is empty.
Types ¶
type ContentType ¶
type ContentType string
const ( UNKNOWN ContentType = "unknown" ROUTER_UPDATE ContentType = "router_update" PLUGIN ContentType = "plugin" RESEED ContentType = "reseed" NEWS ContentType = "news" BLOCKLIST ContentType = "blocklist" )
type SU3 ¶
type SU3 struct { SignatureType SignatureType SignatureLength uint16 ContentLength uint64 FileType FileType ContentType ContentType Version string SignerID string // contains filtered or unexported fields }
type SignatureType ¶
type SignatureType string
const ( DSA_SHA1 SignatureType = "DSA-SHA1" ECDSA_SHA256_P256 SignatureType = "ECDSA-SHA256-P256" ECDSA_SHA384_P384 SignatureType = "ECDSA-SHA384-P384" ECDSA_SHA512_P521 SignatureType = "ECDSA-SHA512-P521" RSA_SHA256_2048 SignatureType = "RSA-SHA256-2048" RSA_SHA384_3072 SignatureType = "RSA-SHA384-3072" RSA_SHA512_4096 SignatureType = "RSA-SHA512-4096" EdDSA_SHA512_Ed25519ph SignatureType = "EdDSA-SHA512-Ed25519ph" )