README ¶
Signing Component Versions
This tour illustrates the basic functionality to sign and verify signatures.
It covers two basic scenarios:
sign
Create, Sign, Transport and Verify a component version.context
Using context settings to configure signing and verification in target repo.
Running the examples
You can call the main program with a config file option (--config <file>
) and the name of the scenario.
The config file should have the following content:
targetRepository:
type: CommonTransportFormat
filePath: /tmp/example06.target.ctf
fileFormat: directory
accessMode: 2
ocmConfig: <your ocm config file>
The actual version of the example just works with the file system target, because it is not possible to specify credentials for the target repository in this simple config file. But, if you specific an OCM config file you can add more credential settings to make target repositories possible requiring credentials.
Walkthrough
Create, Sign, Transport and Verify a component version
As usual, we start with getting access to an OCM context
ctx := ocm.DefaultContext()
Then, we configure this context with optional ocm config defined in our config file. See OCM config scenario in tour 04.
err := ReadConfiguration(ctx, cfg)
if err != nil {
return err
}
To sign a component version we need a private key. For this example, we just create a local keypair. To be able to verify later, we should save the public key, but here we do all this in a single program.
privkey, pubkey, err := rsa.CreateKeyPair()
if err != nil {
return errors.Wrapf(err, "cannot create keypair")
}
And we need a component version to sign. We again compose a component version without a repository (see tour02 example 2).
cv := composition.NewComponentVersion(ctx, "acme.org/example6", "v0.1.0")
// just use the same component version setup again
err = setupVersion(cv)
if err != nil {
return errors.Wrapf(err, "version composition")
}
fmt.Printf("*** composition version ***\n")
err = describeVersion(cv)
Now, let's sign the component version.
There might be multiple signatures, therefore every signature
has a name (here acme.org
). Keys are always specified for
a dedicated signature name. The signing process can be influenced by
several options. Here, we just provide the private key to be used in an ad-hoc manner.
Later, we will see how everything can be preconfigured in a signing context.
_, err = signing.SignComponentVersion(cv, "acme.org", signing.PrivateKey("acme.org", privkey))
if err != nil {
return errors.Wrapf(err, "cannot sign component version")
}
fmt.Printf("*** signed composition version ***\n")
err = describeVersion(cv)
Now, we add the signed component version to a target repository. Here, we just reuse the code from tour02
fmt.Printf("target repository is %s\n", string(cfg.Target))
target, err := ctx.RepositoryForConfig(cfg.Target, nil)
if err != nil {
return errors.Wrapf(err, "cannot open repository")
}
defer target.Close()
err = target.AddComponentVersion(cv, true)
if err != nil {
return errors.Wrapf(err, "cannot store signed version")
}
Let's check the target for the new component version.
tcv, err := target.LookupComponentVersion("acme.org/example6", "v0.1.0")
if err != nil {
return errors.Wrapf(err, "transported version not found")
}
defer tcv.Close()
// please be aware that the signature should be stored.
fmt.Printf("*** target version in transportation target\n")
err = describeVersion(tcv)
if err != nil {
return errors.Wrapf(err, "describe failed")
}
Please note, that the version now contains a signature.
Finally, we check whether the signature is still valid for the target version.
_, err = signing.VerifyComponentVersion(cv, "acme.org", signing.PublicKey("acme.org", pubkey))
if err != nil {
return errors.Wrapf(err, "verification failed")
} else {
fmt.Printf("verification succeeded\n")
}
Using Context Settings to Configure Signing
Instead of providing all signing relevant information directly with the signing or verification calls, it is possible to preconfigure various information at the OCM context.
As usual, we start with getting access to an OCM context
ctx := ocm.DefaultContext()
Then, we configure this context with optional ocm config defined in our config file. See OCM config scenario in tour 04.
err := ReadConfiguration(ctx, cfg)
if err != nil {
return err
}
To sign a component version we need a private key. For this example, we again just create a local keypair. To be able to verify later, we should save the public key, but here we do all this in a single program.
privkey, pubkey, err := rsa.CreateKeyPair()
if err != nil {
return errors.Wrapf(err, "cannot create keypair")
}
Finally, we create a component version in our target repository. The called function
err = prepareComponentInRepo(ctx, cfg)
if err != nil {
return errors.Wrapf(err, "cannot prepare component version in target repo")
}
executes the same coding already shown in the previous example.
Signing Using Manual Context Settings
After this preparation we now configure the signing part of the OCM context. Every OCM context features a signing registry, which provides available signers and hashers, but also keys and certificates for various purposes. It is always asked if a key is required, which is not explicitly given to a signing/verification call.
This context part is implemented as additional attribute stored along
with the context. Attributes are always implemented as a separate package
containing the attribute structure, its deserialization and
a Get(Context)
function to retrieve the attribute for the context.
This way new arbitrary attributes for various use cases can be added
without the need to change the context interface.
siginfo := signingattr.Get(ctx)
Now, we manually add the keys to our context.
siginfo.RegisterPrivateKey("acme.org", privkey)
siginfo.RegisterPublicKey("acme.org", pubkey)
We are prepared now and can sign any component version without specifying further options
in any repository for the signature name acme.org
.
Therefore, we just get the component version from the prepared repository
fmt.Printf("repository is %s\n", string(cfg.Target))
repo, err := ctx.RepositoryForConfig(cfg.Target, nil)
if err != nil {
return errors.Wrapf(err, "cannot open repository")
}
defer repo.Close()
cv, err := repo.LookupComponentVersion("acme.org/example6", "v0.1.0")
if err != nil {
return errors.Wrapf(err, "version not found")
}
defer cv.Close()
and finally sign it. We don't need to present the key, here. It is taken from the context.
_, err = signing.SignComponentVersion(cv, "acme.org")
if err != nil {
return errors.Wrapf(err, "cannot sign component version")
}
The same way we can just call VerifyComponentVersion
to
verify the signature.
_, err = signing.VerifyComponentVersion(cv, "acme.org")
if err != nil {
return errors.Wrapf(err, "verification failed")
} else {
fmt.Printf("verification succeeded\n")
}
Configuring Keys with OCM Configuration File
Manually adding keys to the signing attribute might simplify the call to possibly multiple signing/verification calls, but it does not help to provide keys via an external configuration (for example for using the OCM CLI). In tour04 we have seen how arbitrary configuration possibilities can be added. The signing attribute uses this mechanism to configure itself by providing an own configuration object, which can be used to feed keys (and certificates) into the signing attribute of an OCM context.
sigcfg := signingattr.New()
It provides methods to add elements like keys and certificates, which convert these elements into a (de-)serializable form.
sigcfg.AddPrivateKey("acme.org", privkey)
sigcfg.AddPublicKey("acme.org", pubkey)
ocmcfg := configcfg.New()
ocmcfg.AddConfig(sigcfg)
By adding this config to a generic configuration object you get an OCM config usable to predefine keys for your CLI.
data, err := runtime.DefaultYAMLEncoding.Marshal(ocmcfg)
if err != nil {
return err
}
fmt.Printf("ocm config file configuring standard keys:\n--- begin ocmconfig ---\n%s--- end ocmconfig ---\n", string(data))
And here is a sample output containing the public and private key.
configurations:
- privateKeys:
acme.org:
stringdata: |
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAx0v6JLoV1mrYpX1H86G5bMVBF2ftyxy/IJh1WJMv6xp6q3aK
y+WQEJu/O6Lnh9XdZWRpz36dTJ9AnraEF/kNktJW9zMQQjWpXqjM3nwL5Eczc1ek
jkK6Xa5NZ+HC2lhgPXAsYhkF93EDPd4lKn9g+E68KKPrBy/FDdFnu1YL3tSERF65
FIJKLftKEPTJEjlHtG0bxdLWvEaTgLg4yxiw8ZMBBO1A1nyqf5zdQkxAEbpNuSGh
tinvqZ1CNhhbnechWxFp3XgDV+rKT5s1PWdgNgM4b26v4ocH+4b3iugi53WDcdD1
1TrIeh3Tv5gCVyd3qdrJVOr4/JH4Ut8Pmrx3SwIDAQABAoIBAAJH3k75SjKv+la6
fk5NdX/HKh2IdPI0HAPVetJOrOe1392Cd8gpkmJ+Rcv660dkrSnx4jwbqNUtpWGr
mQtlMECT46bkkLURRCTvLZkGNmSgY/hX8mwmW1ejHQOpU7+H72IEnJ1qx+SzCGR2
3FoGJyfwTrrwVUo5w7mKwfMk4vHj24muIsc8Jcvy7zQsuDHpS+QKTCppJjSO68ZQ
XYxonlb+a9alQdoN+CDJ4ic5N7YTs1ofTSnkqBmIT6fW8CcYpJWBh2Km/shzh1Ll
9mqda0p9HJRmBZ9q1+Jy5W5g7P3O0rKoS1XAXqFnbG0Ux9AMX9GG8xEo7fhG+UuQ
IpEke5ECgYEA8BtlcYPkmmsZzeEmO/hvLZibfO+PShHOnb2XyA6+jM+3rlAaFdDv
qVFhS3cuGFpQX1csvPamQ0+ZhoOCAMiyZ2UkurMR6HaBlCL5akn53LiIOX+rsrUV
f4cGpFSnraMV6sc2D2hK68id9plZheDoGVlI55MtvnfIv/N0M26JWSUCgYEA1H0N
mmHg6x7KkEnGO6Xo47jElFrvXwbtQ9jsmsv/F0s9V821pMVw8/OE+d0U9h9hQFz0
dGIM5EQHbHTx1bN71TdsCeYAlJWHU2Ifoyi7XqhZ3PhuVMAOyN4MUAvN/C9GKkBz
/Z7fWQQVbQUQcUGeTfbg3k5eoo4FcNnPKu0JO68CgYEAzEmC9iIRzpBxVAnMThoB
/flp0dLBR3P/J5a4HS7uUUAqN9VPXGB4iMcE0QCF55Jv765sEhqJO5vuM9SQN7qK
kA4uQes5wV+SwEdBjn2CaZlXzhQiMdqAgBCSRh8Ay2uGqkr0ZAeINzRpsfanhJDm
6SpeLSm8MeIYm7i3lUrm8UECgYAe58FevvWzvNrBebl3W34wAOO2oDNIov1HbPmc
2ibUAIF/j8/nk0AGe1jP7rPpyE6gyeRUOR6e5LYftDKoXl6YeGMiXW2gLs9r9U2c
sYPvFJVdalTBxt1focwwqEbhcw7FfnJgZQcfL1TecmodzulzdYDnVIa3JejsrQFQ
wQEiyQKBgDIIT2zJJtidLfs2m1wffjN+DqnhDvG/0rD9ATNYVdAdMijijsBptx4B
aY+Q1cwPcpS/YhF+NQv/CahUu+0gLGfiVjf+bkRlfvCyPYZgoSPsm3IBIHahPAoE
5G+GqidX8uul4/ZtUXzZl/kbygCB9PGRaf93rXcyW2OUxF2kCOxF
-----END RSA PRIVATE KEY-----
publicKeys:
acme.org:
stringdata: |
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAx0v6JLoV1mrYpX1H86G5bMVBF2ftyxy/IJh1WJMv6xp6q3aKy+WQ
EJu/O6Lnh9XdZWRpz36dTJ9AnraEF/kNktJW9zMQQjWpXqjM3nwL5Eczc1ekjkK6
Xa5NZ+HC2lhgPXAsYhkF93EDPd4lKn9g+E68KKPrBy/FDdFnu1YL3tSERF65FIJK
LftKEPTJEjlHtG0bxdLWvEaTgLg4yxiw8ZMBBO1A1nyqf5zdQkxAEbpNuSGhtinv
qZ1CNhhbnechWxFp3XgDV+rKT5s1PWdgNgM4b26v4ocH+4b3iugi53WDcdD11TrI
eh3Tv5gCVyd3qdrJVOr4/JH4Ut8Pmrx3SwIDAQAB
-----END RSA PUBLIC KEY-----
type: keys.config.ocm.software
type: generic.config.ocm.software
Documentation ¶
There is no documentation for this package.