From 38401a699f58feac0f7f163a6bead7772b26e3a0 Mon Sep 17 00:00:00 2001 From: aljazdb Date: Mon, 11 May 2026 11:03:40 +0200 Subject: [PATCH 1/4] updates to readme --- README.md | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a102da3..1d8a4b7 100644 --- a/README.md +++ b/README.md @@ -72,13 +72,27 @@ SignedData ::= SEQUENCE { ```go // Payload is the structureless data container for all versions of RTU type Payload struct { - // unexported fields + // required info across all versions rtus + validUntil time.Time + transactionID string + + // cpk not nil means, this payload was signed. + // it should be set by signers, before Version.Make is called + cpk CPK + + // optional keys + delegatedUse *bool + sellerName *string + sellerAddr *string + limitDeliverArea *string + consignmentIDs []string + limitConsignments *int } ``` -`Payload` is a structure used to store all relevant data inside an `RTU.Payload`. +`rtu.Payload` is a structure used to store all relevant data inside an `RTU.Payload`. It allows setting and getting of all stored information of an `IOSS-RTU`. See the [Definitions](#definitions) section for additional rules governing these fields. + -It allows setting and getting of all stored information of an `IOSS-RTU` Each `Version` supported in this library should be able to parse its own data structure into `rtu.SchemaPayload`, which is an interface that allows conversion to `rtu.Payload`. See the CONTRIBUTION section for more details on `SchemaPayload` and @@ -88,7 +102,7 @@ how to add a new version ### SignatureAlgorithms -This SDK has a `PublicKey` and `PrivateKey` structure to help join correct CPK and keys to its rightful `SignatureAlgorithm` +This SDK has a `PublicKey` and `PrivateKey` structure to help join correct CPK (compressed public key) and keys to its rightful `SignatureAlgorithm` List of available SignatureAlgorithms: ```go @@ -98,20 +112,20 @@ const ( ) ``` -SignatureAlgorithms define a signature algorithm type. It also implements `Digest` method, which returns a digest of a payload +SignatureAlgorithms define a signature algorithm type. It also implements the `Digest` method, which returns a digest of the payload based on the signature type. Example: `rtu.AlgorithmEcdsaP256` returns a SHA256 digest, to be signed with an ECDSA private key. --- ### CPK -CPK - Compressed Public Key is a raw byte array compressed representation of a public key. +CPK (Compressed Public Key) is a raw byte array compressed representation of a public key. ```go type CPK []byte ``` -It has a method `Parse`, that allows recovery of a publicKey, with a given `SignatureAlgorithm` and returns a `rtu.PublicKey` +It has a method `Parse`, that reconstructs the public key encoded in the CPK using the provided `SignatureAlgorithm`, and returns an `rtu.PublicKey`. Example: For the signature algorithm `rtu.AlgorithmEcdsaP256`, the CPK value is: @@ -124,7 +138,7 @@ var cpk CPK = elliptic.MarshalCompressed(key.Curve, key.X, key.Y) ### Keys -`PublicKey` is the combination of a SignatureAlgorithm with a publicKey `crypto.PublicKey` and a computedCPK `rtu.CPK`. +`rtu.PublicKey` is the combination of a SignatureAlgorithm with a publicKey `crypto.PublicKey` and a computedCPK `rtu.CPK`. ```go type PublicKey struct { @@ -135,7 +149,7 @@ type PublicKey struct { } ``` -`PrivateKey` is the same as `PublicKey` but also adds the correct privateKey into the combination. +`rtu.PrivateKey` extends `rtu.PublicKey` by additionally including the corresponding private key material. ```go type PrivateKey struct { @@ -289,12 +303,16 @@ packedRtu, err := rtu.Sign(rtu.Version1, paylaod, privateKey) `ExternalSigner` is a service, that enables issuers to sign via an external private key. It needs the `rtu.PublicKey` representation of the external signer's public key, and the version of the RTU object it is producing. -You can then use its methods `ComputeDigest` to generate the correct digest to sign and the raw payload, that was constructed from `rtu.Payload`. -Signing the digest with the correct private key, and offering the signature along with the given raw payload into `ConstructSigned` allows the signer -to validate your signature (and validate it was signed with the correct private key) and construct the correct RTU object. +You can use its `ComputeDigest` method to generate the digest that must be signed, as well as the raw payload derived from `rtu.Payload`. + +Once the digest is signed with the appropriate private key, the resulting signature (together with the raw payload) can be passed into `ConstructSigned`. This allows the signer to verify that the signature is valid (produced using the correct private key), and then construct the corresponding RTU object. + +`ConstructSigned` returns a `PackedRTU` for easier handling. + +If you need a `RawRTU`, use `ConstructSignedRaw`. + +If you want a fully parsed `rtu.RTU` object, use `ConstructSignedObj`. -`ConstructSigned` returns a PackedRTU for easier usage, to get a `RawRTU` use `ConstructSignedRaw`, -or if you wish to get an `rtu.RTU` object, use `ConstructSignedObj`. ```go var publicKey rtu.PublicKey // get public key for your signer, import *ecdsa.PublicKey with rtu.NewECPublicKey(publicKey) From c44a49a7755e0f2c544fc11137458b98385b3e24 Mon Sep 17 00:00:00 2001 From: zbrumen Date: Mon, 11 May 2026 13:07:55 +0200 Subject: [PATCH 2/4] added more descriptions to example --- README.md | 34 +++++++++++++++---- internal/examples/external-signer/main.go | 4 +++ internal/examples/signer/main.go | 4 +++ internal/examples/verify/helper.go | 41 +++++++++++++++++++++++ internal/examples/verify/main.go | 37 ++------------------ 5 files changed, 79 insertions(+), 41 deletions(-) create mode 100644 internal/examples/verify/helper.go diff --git a/README.md b/README.md index 1d8a4b7..bd4fde2 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,14 @@ import rtu "github.com/MyNextID/ioss-rtu-go-sdk" This library has 3 main usages: `Sign`, `SignExternally` and `Parse` an IOSSRTU token. -All the examples can be found in the [examples](internal/examples) folder +All the examples can be found in the [examples](internal/examples) folder. + +Short descriptions for examples: +* **external-signer** — Demonstrates how to use `rtu.ExternalSigner` to prepare an unsigned `rtu.Payload`, export its ASN.1 DER encoded payload and digest for signing with an external private key, and reconstruct the final signed `rtu.PackedRTU` from the returned signature. + +* **signer** — Shows how to sign an `rtu.Payload` directly using a `PrivateKey`, producing a fully signed `rtu.PackedRTU` object. + +* **verify** — Demonstrates how to verify an `rtu.PackedRTU` (a Base64URL-encoded ASN.1 DER encoded `*rtu.RTU`) by validating its structure and verifying its signature. --- @@ -102,7 +109,14 @@ how to add a new version ### SignatureAlgorithms -This SDK has a `PublicKey` and `PrivateKey` structure to help join correct CPK (compressed public key) and keys to its rightful `SignatureAlgorithm` +The SDK provides `PublicKey` and `PrivateKey` structs that bind cryptographic keys to their corresponding SignatureAlgorithm. + +`PublicKey` wraps a compressed public key (CPK), the underlying public key implementation (such as `*ecdsa.PublicKey` or `*ed25519.PublicKey`), +and its associated `SignatureAlgorithm`. + +`PrivateKey` embeds a `PublicKey` and extends it with the corresponding private key implementation (such as `*ecdsa.PrivateKey` or `*ed25519.PrivateKey`). + +This design ensures that public/private key pairs are always associated with the correct signature algorithm. List of available SignatureAlgorithms: ```go @@ -254,12 +268,17 @@ NOTE: `ConsignmentIDs` and `LimitConsignments` are exclusive. If both are set, a ## Signers -### SignV1 +This SDK has a `Signer` defined as a function below: -`SignV1` is a `rtu.Signer` function, that signs a `rtu.Payload` with an ECDSA-P256 private key (version 1 only supports that algorithm), -and creates a `rtu.Version1` RTU ```go +type Signer func(payload *Payload, key *PrivateKey) (*RTU, error) +``` + +### SignV1 +`SignV1` is a `rtu.Signer` function, that signs a `rtu.Payload` as a `rtu.Version1` IOSSRTU. +It accepts an ECDSA-P256 private key (version 1 only supports that algorithm) +```go key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { panic(err) @@ -278,8 +297,10 @@ signedRtu, err := rtu.SignV1(payload, privateKey) ### Sign -`Sign` is a helper function, that takes a `rtu.Version`, `rtu.Payload` and `rtu.PrivateKey` variable, and generates a `rtu.PackedRTU` +`Sign` is a ease of use function, that allows `rtu.Version` to be given as a parameter along with `rtu.Payload` and `rtu.PrivateKey`, +to generate a `rtu.PackedRTU` +Usage: ```go key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -295,7 +316,6 @@ payload := rtu.NewPayload("TX_ID", time.Now().Add(time.Hour)).SetDelegatedUse(fa // Sign the payload as an Version1 RTU object, with the given privateKey packedRtu, err := rtu.Sign(rtu.Version1, paylaod, privateKey) - ``` ### External Signer diff --git a/internal/examples/external-signer/main.go b/internal/examples/external-signer/main.go index 44d902d..e7302c9 100644 --- a/internal/examples/external-signer/main.go +++ b/internal/examples/external-signer/main.go @@ -10,6 +10,10 @@ import ( rtu "github.com/MyNextID/ioss-rtu-go-sdk" ) +/* +This example generates an *ecdsa.PrivateKey, prepares an example rtu.Payload, generates a digest and raw payload from ExternalSigner, +hands it off to be signed by "a different service", and uses the raw payload and signature to create a signed rtu.PackedRTU +*/ func main() { // generate an example ecdsa.PrivateKey (you would use your valid IOSS private key here) externalKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) diff --git a/internal/examples/signer/main.go b/internal/examples/signer/main.go index d82c690..b743345 100644 --- a/internal/examples/signer/main.go +++ b/internal/examples/signer/main.go @@ -10,6 +10,10 @@ import ( rtu "github.com/MyNextID/ioss-rtu-go-sdk" ) +/* +This example generates an *ecdsa.PrivateKey, prepares an example rtu.Payload, and signs it with the key, creating an +*rtu.RTU object, which is packed into rtu.PackedRTU (which is ready to be sent) +*/ func main() { // generate an example ecdsa.PrivateKey (you would use your valid IOSS private key here) key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) diff --git a/internal/examples/verify/helper.go b/internal/examples/verify/helper.go new file mode 100644 index 0000000..ce08fde --- /dev/null +++ b/internal/examples/verify/helper.go @@ -0,0 +1,41 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "time" + + rtu "github.com/MyNextID/ioss-rtu-go-sdk" +) + +// A helper function to generate the PackedRTU to parse in this example +func generateAValidPackedRTU() rtu.PackedRTU { + // generate an example ecdsa.PrivateKey (you would use your valid IOSS private key here) + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(err) + } + // build a rtu.PrivateKey + privKey, err := rtu.NewECPrivateKey(key) + if err != nil { + panic(err) + } + // create your RTU payload + txID := "tx-id" + validUntil := time.Now().Add(time.Hour * 24 * 30) + payload := rtu.NewPayload(txID, validUntil). + SetDelegatedUse(false). + SetSellerName("Acme Corp") + // Sign the payload and generate the signed *rtu.RTU object with Version 1 + signedObj, err := rtu.SignV1(payload, privKey) + if err != nil { + panic(err) + } + // pack the signedObj to get the final base64-url encoded IOSSRTU + packedRtu, err := signedObj.Pack() + if err != nil { + panic(err) + } + return packedRtu +} diff --git a/internal/examples/verify/main.go b/internal/examples/verify/main.go index 40b149b..c9c464f 100644 --- a/internal/examples/verify/main.go +++ b/internal/examples/verify/main.go @@ -1,45 +1,14 @@ package main import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "fmt" - "time" rtu "github.com/MyNextID/ioss-rtu-go-sdk" ) -func generateAValidPackedRTU() rtu.PackedRTU { - // generate an example ecdsa.PrivateKey (you would use your valid IOSS private key here) - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - panic(err) - } - // build a rtu.PrivateKey - privKey, err := rtu.NewECPrivateKey(key) - if err != nil { - panic(err) - } - // create your RTU payload - txID := "tx-id" - validUntil := time.Now().Add(time.Hour * 24 * 30) - payload := rtu.NewPayload(txID, validUntil). - SetDelegatedUse(false). - SetSellerName("Acme Corp") - // Sign the payload and generate the signed *rtu.RTU object with Version 1 - signedObj, err := rtu.SignV1(payload, privKey) - if err != nil { - panic(err) - } - // pack the signedObj to get the final base64-url encoded IOSSRTU - packedRtu, err := signedObj.Pack() - if err != nil { - panic(err) - } - return packedRtu -} - +/* +This example gets a packedRtu (rtu.PackedRTU) and parses it (verify signature and validate structure) to get rtu.Payload +*/ func main() { // get your IOSSRTU from a source, in this example we generate a valid one var packedRtu rtu.PackedRTU = generateAValidPackedRTU() From 7b22619db6cf1790895f58ac079b6b9641f7ff46 Mon Sep 17 00:00:00 2001 From: zbrumen Date: Mon, 11 May 2026 13:19:27 +0200 Subject: [PATCH 3/4] removed contribution mention from README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index bd4fde2..0364fe5 100644 --- a/README.md +++ b/README.md @@ -102,9 +102,7 @@ type Payload struct { Each `Version` supported in this library should be able to parse its own data structure into `rtu.SchemaPayload`, which is -an interface that allows conversion to `rtu.Payload`. See the CONTRIBUTION section for more details on `SchemaPayload` and -how to add a new version - +an interface that allows conversion to `rtu.Payload`. --- ### SignatureAlgorithms From 66a17dea2e9ce206044f8fe6e60b591efcb4e51d Mon Sep 17 00:00:00 2001 From: gale8 <36955046+gale8@users.noreply.github.com> Date: Thu, 21 May 2026 13:46:03 +0200 Subject: [PATCH 4/4] Update README.md - fixed some typos and grammar mistakes --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0364fe5..1180941 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ latest version: go get github.com/MyNextID/ioss-rtu-go-sdk@latest ``` -Next, include the library in you project: +Next, include the library in your project: ```go import rtu "github.com/MyNextID/ioss-rtu-go-sdk" ``` @@ -103,6 +103,7 @@ type Payload struct { Each `Version` supported in this library should be able to parse its own data structure into `rtu.SchemaPayload`, which is an interface that allows conversion to `rtu.Payload`. + --- ### SignatureAlgorithms @@ -178,7 +179,7 @@ For future improvements to the RTU structure and/or adding signature support, ea which defines the signature type, signature algorithms supported, maxRTUSize, maxRTUPayload size and payload structure along with all the validation rules for the fields inside the correct payload structure. -Currently this library support IOSS-RTU Versions: +Currently this library supports IOSS-RTU Versions: ```go const ( Version1 Version = 1 @@ -295,7 +296,7 @@ signedRtu, err := rtu.SignV1(payload, privateKey) ### Sign -`Sign` is a ease of use function, that allows `rtu.Version` to be given as a parameter along with `rtu.Payload` and `rtu.PrivateKey`, +`Sign` is an ease-of-use function, that allows `rtu.Version` to be given as a parameter along with `rtu.Payload` and `rtu.PrivateKey`, to generate a `rtu.PackedRTU` Usage: @@ -313,7 +314,7 @@ if err != nil { payload := rtu.NewPayload("TX_ID", time.Now().Add(time.Hour)).SetDelegatedUse(false) // Sign the payload as an Version1 RTU object, with the given privateKey -packedRtu, err := rtu.Sign(rtu.Version1, paylaod, privateKey) +packedRtu, err := rtu.Sign(rtu.Version1, payload, privateKey) ``` ### External Signer @@ -371,7 +372,7 @@ payload, err := signedObj.Parse(true) if err != nil { // error here means the payload was malformed, signature was bad or the payload structure fields were invalid // (validUntil field is no longer valid, transactionId field is empty or is too large, CPK malformed etc.) - // validation errors return an *rtu.ValidationError error, which has the exact fields that was bad + // validation errors return an *rtu.ValidationError error, which has the exact fields that were invalid panic(err) }