Skip to content

Commit

Permalink
signing support for rsa-pss (#640)
Browse files Browse the repository at this point in the history
## Description

Add support for rsa-pss signing:
- direct local signing
- via signing server


## What type of PR is this? (check all applicable)

- [x] 🍕 Feature
- [ ] 🐛 Bug Fix
- [x] 📝 Documentation Update
- [ ] 🎨 Style
- [ ] 🧑‍💻 Code Refactor
- [ ] 🔥 Performance Improvements
- [x] ✅ Test
- [ ] 🤖 Build
- [ ] 🔁 CI
- [ ] 📦 Chore (Release)
- [ ] ⏩ Revert

## Related Tickets & Documents

<!-- 
Please use this format link issue numbers: Fixes #123

https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword
-->
- Related Issue # (issue)
- Closes # (issue)
- Fixes # (issue)
> Remove if not applicable

## Screenshots

<!-- Visual changes require screenshots -->


## Added tests?

- [ ] 👍 yes
- [ ] 🙅 no, because they aren't needed
- [ ] 🙋 no, because I need help
- [ ] Separate ticket for tests # (issue/pr)

Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration


## Added to documentation?

- [ ] 📜 README.md
- [ ] 🙅 no documentation needed

## Checklist:

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
  • Loading branch information
mandelsoft authored Feb 16, 2024
1 parent 4169646 commit 84bb593
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 23 deletions.
2 changes: 1 addition & 1 deletion cmds/ocm/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ default credential, always used if no dedicated match is found.
For example:
<center>
<pre>--cred :type=ociRegistry --cred :hostname=ghcr.io --cred username=mandelsoft --cred password=xyz</pre>
<pre>--cred :type=OCIRegistry --cred :hostname=ghcr.io --cred username=mandelsoft --cred password=xyz</pre>
</center>
With the option <code>-X</code> it is possible to pass global settings of the
Expand Down
10 changes: 5 additions & 5 deletions cmds/ocm/commands/misccmds/rsakeypair/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ created rsa key pair key.priv[key.pub]
Issuer: ISSUER,
}
d := digest.FromBytes([]byte("digest"))
sig, err := rsa.Handler{}.Sign(defaultContext, d.Hex(), sctx)
sig, err := rsa.NewHandler().Sign(defaultContext, d.Hex(), sctx)
Expect(err).To(Succeed())
Expect(sig.Algorithm).To(Equal(rsa.Algorithm))
Expect(sig.MediaType).To(Equal(rsa.MediaType))

err = rsa.Handler{}.Verify(d.Hex(), sig, &signing.DefaultSigningContext{PublicKey: pub})
err = rsa.NewHandler().Verify(d.Hex(), sig, &signing.DefaultSigningContext{PublicKey: pub})
Expect(err).To(Succeed())
})

Expand All @@ -90,12 +90,12 @@ created rsa key pair key.priv[key.cert]
Issuer: ISSUER,
}
d := digest.FromBytes([]byte("digest"))
sig, err := rsa.Handler{}.Sign(defaultContext, d.Hex(), sctx)
sig, err := rsa.NewHandler().Sign(defaultContext, d.Hex(), sctx)
Expect(err).To(Succeed())
Expect(sig.Algorithm).To(Equal(rsa.Algorithm))
Expect(sig.MediaType).To(Equal(rsa.MediaType))

err = rsa.Handler{}.Verify(d.Hex(), sig, &signing.DefaultSigningContext{PublicKey: pub})
err = rsa.NewHandler().Verify(d.Hex(), sig, &signing.DefaultSigningContext{PublicKey: pub})
Expect(err).To(Succeed())
})

Expand Down Expand Up @@ -137,7 +137,7 @@ created encrypted rsa key pair key.priv[key.pub][key.priv.ekey]
Issuer: ISSUER,
}
d := digest.FromBytes([]byte("digest"))
Must(rsa.Handler{}.Sign(defaultContext, d.Hex(), sctx))
Must(rsa.NewHandler().Sign(defaultContext, d.Hex(), sctx))

buf.Reset()
Expect(env.CatchOutput(buf).Execute("create", "rsakeypair", "-e", KEYNAME, "other.priv")).To(Succeed())
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/ocm.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ default credential, always used if no dedicated match is found.
For example:

<center>
<pre>--cred :type=ociRegistry --cred :hostname=ghcr.io --cred username=mandelsoft --cred password=xyz</pre>
<pre>--cred :type=OCIRegistry --cred :hostname=ghcr.io --cred username=mandelsoft --cred password=xyz</pre>
</center>

With the option <code>-X</code> it is possible to pass global settings of the
Expand Down
22 changes: 22 additions & 0 deletions docs/reference/ocm_attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,28 @@ OCM library:

Directory to look for OCM plugin executables.

- <code>github.com/mandelsoft/ocm/rootcerts</code>: *JSON*

General root certificate settings given as JSON document with the following
format:

<pre>
{
"rootCertificates"": [
{
"data": ""&lt;base64>"
},
{
"path": ""&lt;file path>"
}
],
</pre>

One of following data fields are possible:
- <code>data</code>: base64 encoded binary data
- <code>stringdata</code>: plain text data
- <code>path</code>: a file path to read the data from

- <code>github.com/mandelsoft/ocm/signing</code>: *JSON*

Public and private Key settings given as JSON document with the following
Expand Down
11 changes: 11 additions & 0 deletions docs/reference/ocm_configfile.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,17 @@ The following configuration types are supported:
config: &lt;arbitrary configuration structure>
disableAutoRegistration: &lt;boolean flag to disable auto registration for up- and download handlers>
</pre>
- <code>rootcerts.config.ocm.software</code>
The config type <code>rootcerts.config.ocm.software</code> can be used to define
general root certificates. A certificate value might be given by one of the fields:
- <code>path</code>: path of file with key data
- <code>data</code>: base64 encoded binary data
- <code>stringdata</code>: data a string parsed by key handler

<pre>
rootCertificates:
- path: &lt;file path>
</pre>
- <code>scripts.ocm.config.ocm.software</code>
The config type <code>scripts.ocm.config.ocm.software</code> can be used to define transfer scripts:

Expand Down
1 change: 1 addition & 0 deletions docs/reference/ocm_logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The following *realms* are used by the command line tool:
- <code>ocm</code>: general realm used for the ocm go library.
- <code>ocm/accessmethod/ociartifact</code>: access method ociArtifact
- <code>ocm/compdesc</code>: component descriptor handling
- <code>ocm/config</code>: configuration management
- <code>ocm/context</code>: context lifecycle
- <code>ocm/credentials/dockerconfig</code>: docker config handling as credential repository
- <code>ocm/credentials/vault</code>: HashiCorp Vault Access
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/ocm_sign_componentversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ given signature name will be verified, instead of recreated.

The following signing types are supported with option <code>--algorithm</code>:
- <code>RSASSA-PKCS1-V1_5</code> (default)
- <code>RSASSA-PSS</code>
- <code>rsa-signingservice</code>
- <code>rsapss-signingservice</code>
- <code>sigstore</code>


Expand Down
45 changes: 45 additions & 0 deletions pkg/contexts/ocm/signing/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package signing_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/open-component-model/ocm/pkg/testutils"

"github.com/open-component-model/ocm/pkg/blobaccess"
"github.com/open-component-model/ocm/pkg/contexts/ocm"
v1 "github.com/open-component-model/ocm/pkg/contexts/ocm/compdesc/meta/v1"
"github.com/open-component-model/ocm/pkg/contexts/ocm/repositories/composition"
"github.com/open-component-model/ocm/pkg/contexts/ocm/resourcetypes"
"github.com/open-component-model/ocm/pkg/contexts/ocm/signing"
"github.com/open-component-model/ocm/pkg/mime"
"github.com/open-component-model/ocm/pkg/signing/handlers/rsa"
rsa_pss "github.com/open-component-model/ocm/pkg/signing/handlers/rsa-pss"
"github.com/open-component-model/ocm/pkg/signing/signutils"
)

var _ = Describe("Simple signing handlers", func() {
Context("", func() {
ctx := ocm.DefaultContext()

var cv ocm.ComponentVersionAccess
var pub signutils.GenericPublicKey
var priv signutils.GenericPrivateKey

BeforeEach(func() {
priv, pub = Must2(rsa.CreateKeyPair())
cv = composition.NewComponentVersion(ctx, COMPONENTA, VERSION)
MustBeSuccessful(cv.SetResourceBlob(ocm.NewResourceMeta("blob", resourcetypes.PLAIN_TEXT, v1.LocalRelation), blobaccess.ForString(mime.MIME_TEXT, "test data"), "", nil))
})

DescribeTable("rsa handlers", func(kind string) {
Must(signing.SignComponentVersion(cv, "signature", signing.PrivateKey("signature", priv)))
Must(signing.VerifyComponentVersion(cv, "signature", signing.PublicKey("signature", pub)))
},
Entry("rsa", rsa.Algorithm),
Entry("rsapss", rsa_pss.Algorithm),
)
})
})
2 changes: 2 additions & 0 deletions pkg/signing/handlers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package handlers

import (
_ "github.com/open-component-model/ocm/pkg/signing/handlers/rsa"
_ "github.com/open-component-model/ocm/pkg/signing/handlers/rsa-pss"
_ "github.com/open-component-model/ocm/pkg/signing/handlers/rsa-pss-signingservice"
_ "github.com/open-component-model/ocm/pkg/signing/handlers/rsa-signingservice"
_ "github.com/open-component-model/ocm/pkg/signing/handlers/sigstore"
_ "github.com/sigstore/cosign/v2/pkg/providers/all"
Expand Down
34 changes: 34 additions & 0 deletions pkg/signing/handlers/rsa-pss-signingservice/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package rsa_pss_signingservice

import (
"github.com/open-component-model/ocm/pkg/signing"
"github.com/open-component-model/ocm/pkg/signing/handlers/rsa"
rsa_signingservice "github.com/open-component-model/ocm/pkg/signing/handlers/rsa-signingservice"
)

// Algorithm defines the type for the RSA PKCS #1 v1.5 signature algorithm.
const (
Algorithm = rsa.Algorithm
Name = "rsapss-signingservice"
)

// SignaturePEMBlockAlgorithmHeader defines the header in a signature pem block where the signature algorithm is defined.
const SignaturePEMBlockAlgorithmHeader = rsa_signingservice.SignaturePEMBlockAlgorithmHeader

func init() {
signing.DefaultHandlerRegistry().RegisterSigner(Name, NewHandler())
}

func NewHandler() signing.Signer {
return rsa_signingservice.NewHandlerFor(Algorithm)
}

type Key = rsa_signingservice.Key

func PrivateKey(k interface{}) (*Key, error) {
return rsa_signingservice.PrivateKey(k)
}
47 changes: 47 additions & 0 deletions pkg/signing/handlers/rsa-pss/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Open Component Model contributors.
//
// SPDX-License-Identifier: Apache-2.0

package rsa_pss

import (
"crypto"
"crypto/rsa"
"io"

"github.com/open-component-model/ocm/pkg/signing"
rsahandler "github.com/open-component-model/ocm/pkg/signing/handlers/rsa"
"github.com/open-component-model/ocm/pkg/signing/signutils"
)

// Algorithm defines the type for the RSA PKCS #1 v1.5 signature algorithm.
const Algorithm = "RSASSA-PSS"

// MediaType defines the media type for a plain RSA-PSS signature.
const MediaType = "application/vnd.ocm.signature.rsa.pss"

// MediaTypePEM is used if the signature contains the public key certificate chain.
const MediaTypePEM = signutils.MediaTypePEM

func init() {
signing.DefaultHandlerRegistry().RegisterSigner(Algorithm, NewHandler())
}

func NewHandler() signing.SignatureHandler {
return rsahandler.NewHandlerFor(RSASSA_PSS)
}

var RSASSA_PSS = &rsahandler.Method{
Algorithm: Algorithm,
MediaType: MediaType,
Sign: sign,
Verify: verify,
}

func sign(rand io.Reader, priv *rsa.PrivateKey, hash crypto.Hash, digest []byte) ([]byte, error) {
return rsa.SignPSS(rand, priv, hash, digest, nil)
}

func verify(pub *rsa.PublicKey, hash crypto.Hash, digest []byte, sig []byte) error {
return rsa.VerifyPSS(pub, hash, digest, sig, nil)
}
18 changes: 13 additions & 5 deletions pkg/signing/handlers/rsa-signingservice/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,28 @@ type Key struct {
const SignaturePEMBlockAlgorithmHeader = "Algorithm"

func init() {
signing.DefaultHandlerRegistry().RegisterSigner(Name, Handler{})
signing.DefaultHandlerRegistry().RegisterSigner(Name, NewHandler())
}

// Handler is a signatures.Signer compatible struct to sign with RSASSA-PKCS1-V1_5.
// using a signature service.
type Handler struct{}
type Handler struct {
algo string
}

func NewHandlerFor(algo string) signing.Signer {
return &Handler{algo}
}

var _ Handler = Handler{}
func NewHandler() signing.Signer {
return &Handler{Algorithm}
}

func (h Handler) Algorithm() string {
func (h *Handler) Algorithm() string {
return Algorithm
}

func (h Handler) Sign(cctx credentials.Context, digest string, sctx signing.SigningContext) (signature *signing.Signature, err error) {
func (h *Handler) Sign(cctx credentials.Context, digest string, sctx signing.SigningContext) (signature *signing.Signature, err error) {
privateKey, err := PrivateKey(sctx.GetPrivateKey())
if err != nil {
return nil, errors.Wrapf(err, "invalid signing server access configuration")
Expand Down
2 changes: 1 addition & 1 deletion pkg/signing/handlers/rsa/certhelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
)

func CreateRootCertificate(sub *pkix.Name, validity time.Duration) (*x509.Certificate, *PrivateKey, error) {
capriv, _, err := Handler{}.CreateKeyPair()
capriv, _, err := CreateKeyPair()
if err != nil {
return nil, nil, err
}
Expand Down
Loading

0 comments on commit 84bb593

Please sign in to comment.