1
0
Fork 0
mirror of https://github.com/gocsaf/csaf.git synced 2025-12-22 18:15:42 +01:00

Merge branch 'main' into dev-improve-client-certs

This commit is contained in:
Bernhard Reiter 2022-04-08 10:06:12 +02:00
commit 96f4d57b76
No known key found for this signature in database
GPG key ID: 2B7BA3BF9BC3A554
24 changed files with 735 additions and 93 deletions

19
.github/workflows/generate-markdown.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: generate-markdown
on:
push:
branches:
- "main"
- "build-scripts"
pull_request:
branches:
- "main"
jobs:
auto-update-readme:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Markdown autodocs
uses: dineshsonachalam/markdown-autodocs@v1.0.4
with:
output_file_paths: '[./README.md, ./docs/*.md]'

43
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: Publish Go binaries to github release
on:
release:
types: [created]
jobs:
releases-matrix:
name: Release Go Binary
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, windows]
goarch: [amd64]
steps:
- uses: actions/checkout@v2
- uses: wangyoucao577/go-release-action@v1.25
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "latest"
build_flags: -v
project_path: ./cmd/csaf_checker
binary_name: csaf_checker
- uses: wangyoucao577/go-release-action@v1.25
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "latest"
build_flags: -v
project_path: ./cmd/csaf_provider
binary_name: csaf_provider
- uses: wangyoucao577/go-release-action@v1.25
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "latest"
build_flags: -v
project_path: ./cmd/csaf_uploader
binary_name: csaf_uploader

View file

@ -41,7 +41,9 @@ Following options are supported:
| -i, --password-interactive | Enter password interactively | | -i, --password-interactive | Enter password interactively |
| -I, --passphrase-interacive | Enter passphrase interactively | | -I, --passphrase-interacive | Enter passphrase interactively |
| -c, --config=INI-FILE | Path to config ini file | | -c, --config=INI-FILE | Path to config ini file |
| --insecure | Do not check TSL certificates from provider | | --insecure | Do not check TLS certificates from provider |
| --client-cert | TLS client certificate file (PEM encoded data) |
| --client-key | TLS client private key file (PEM encoded data) |
| -h, --help | Show help | | -h, --help | Show help |
E.g. creating the initial directiories and files E.g. creating the initial directiories and files

View file

@ -24,9 +24,11 @@ import (
var reportHTML string var reportHTML string
type options struct { type options struct {
Output string `short:"o" long:"output" description:"File name of the generated report" value-name:"REPORT-FILE"` Output string `short:"o" long:"output" description:"File name of the generated report" value-name:"REPORT-FILE"`
Format string `short:"f" long:"format" choice:"json" choice:"html" description:"Format of report" default:"json"` Format string `short:"f" long:"format" choice:"json" choice:"html" description:"Format of report" default:"json"`
Insecure bool `long:"insecure" description:"Do not check TSL certificates from provider"` Insecure bool `long:"insecure" description:"Do not check TLS certificates from provider"`
ClientCert *string `long:"client-cert" description:"TLS client certificate file (PEM encoded data)" value-name:"CERT-FILE"`
ClientKey *string `long:"client-key" description:"TLS client private key file (PEM encoded data)" value-name:"KEY-FILE"`
} }
func errCheck(err error) { func errCheck(err error) {
@ -135,6 +137,11 @@ func main() {
return return
} }
if (opts.ClientCert != nil && opts.ClientKey == nil) || (opts.ClientCert == nil && opts.ClientKey != nil) {
log.Println("Both client-key and client-cert options must be set for the authentication.")
return
}
p := newProcessor(opts) p := newProcessor(opts)
report, err := p.run(buildReporters(), domains) report, err := p.run(buildReporters(), domains)

View file

@ -230,15 +230,20 @@ func (p *processor) httpClient() *http.Client {
p.client = &http.Client{ p.client = &http.Client{
CheckRedirect: p.checkRedirect, CheckRedirect: p.checkRedirect,
} }
var tlsConfig tls.Config
if p.opts.Insecure { if p.opts.Insecure {
p.client.Transport = &http.Transport{ tlsConfig.InsecureSkipVerify = true
TLSClientConfig: &tls.Config{ }
InsecureSkipVerify: true, if p.opts.ClientCert != nil && p.opts.ClientKey != nil {
}, cert, err := tls.LoadX509KeyPair(*p.opts.ClientCert, *p.opts.ClientKey)
} if err != nil {
log.Fatal(err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
p.client.Transport = &http.Transport{
TLSClientConfig: &tlsConfig,
} }
return p.client return p.client
} }

View file

@ -40,11 +40,13 @@ type options struct {
Key *string `short:"k" long:"key" description:"OpenPGP key to sign the CSAF files" value-name:"KEY-FILE"` Key *string `short:"k" long:"key" description:"OpenPGP key to sign the CSAF files" value-name:"KEY-FILE"`
Password *string `short:"p" long:"password" description:"Authentication password for accessing the CSAF provider" value-name:"PASSWORD"` Password *string `short:"p" long:"password" description:"Authentication password for accessing the CSAF provider" value-name:"PASSWORD"`
Passphrase *string `short:"P" long:"passphrase" description:"Passphrase to unlock the OpenPGP key" value-name:"PASSPHRASE"` Passphrase *string `short:"P" long:"passphrase" description:"Passphrase to unlock the OpenPGP key" value-name:"PASSPHRASE"`
ClientCert *string `long:"client-cert" description:"TLS client certificate file (PEM encoded data)" value-name:"CERT-FILE.crt"`
ClientKey *string `long:"client-key" description:"TLS client private key file (PEM encoded data)" value-name:"KEY-FILE.pem"`
PasswordInteractive bool `short:"i" long:"password-interactive" description:"Enter password interactively" no-ini:"true"` PasswordInteractive bool `short:"i" long:"password-interactive" description:"Enter password interactively" no-ini:"true"`
PassphraseInteractive bool `short:"I" long:"passphrase-interacive" description:"Enter passphrase interactively" no-ini:"true"` PassphraseInteractive bool `short:"I" long:"passphrase-interacive" description:"Enter passphrase interactively" no-ini:"true"`
Insecure bool `long:"insecure" description:"Do not check TSL certificates from provider"` Insecure bool `long:"insecure" description:"Do not check TLS certificates from provider"`
Config *string `short:"c" long:"config" description:"Path to config ini file" value-name:"INI-FILE" no-ini:"true"` Config *string `short:"c" long:"config" description:"Path to config ini file" value-name:"INI-FILE" no-ini:"true"`
} }
@ -111,17 +113,29 @@ func newProcessor(opts *options) (*processor, error) {
return &p, nil return &p, nil
} }
// httpClient initializes the http client according // httpClient initializes the http.Client according to the "Insecure" flag
// to the "Insecure" flag option and returns it. // and the TLS client files for authentication and returns it.
func (p *processor) httpClient() *http.Client { func (p *processor) httpClient() *http.Client {
var client http.Client var client http.Client
var tlsConfig tls.Config
if p.opts.Insecure { if p.opts.Insecure {
client.Transport = &http.Transport{ tlsConfig.InsecureSkipVerify = true
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
} }
if p.opts.ClientCert != nil && p.opts.ClientKey != nil {
cert, err := tls.LoadX509KeyPair(*p.opts.ClientCert, *p.opts.ClientKey)
if err != nil {
log.Fatal(err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
client.Transport = &http.Transport{
TLSClientConfig: &tlsConfig,
}
return &client return &client
} }
@ -257,7 +271,7 @@ func (p *processor) uploadRequest(filename string) (*http.Request, error) {
return req, nil return req, nil
} }
// process attemps to upload a file filename to the server. // process attemps to upload a file to the server.
// It prints the response messages. // It prints the response messages.
func (p *processor) process(filename string) error { func (p *processor) process(filename string) error {
@ -365,6 +379,11 @@ func main() {
check(readInteractive("Enter OpenPGP passphrase: ", &opts.Passphrase)) check(readInteractive("Enter OpenPGP passphrase: ", &opts.Passphrase))
} }
if (opts.ClientCert != nil && opts.ClientKey == nil) || (opts.ClientCert == nil && opts.ClientKey != nil) {
log.Println("Both client-key and client-cert options must be set for the authentication.")
return
}
p, err := newProcessor(&opts) p, err := newProcessor(&opts)
check(err) check(err)

View file

@ -5,29 +5,29 @@ a web browser.
### Configure nginx ### Configure nginx
Assuming the relevant server block is in `/etc/nginx/sites-enabled/default` and the CA used to verify the client certificates is under `/etc/ssl/`, Assuming the relevant server block is in `/etc/nginx/sites-enabled/default` and the CA used to verify the client certificates is under `/etc/ssl/`,
adjust it like shown in the following example: adjust the content of the `server{}` block like shown in the following example:
<!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/TLSClientConfigsForITest.sh&lines=25-40) -->
<!-- The below code snippet is automatically added from ../docs/scripts/TLSClientConfigsForITest.sh -->
```sh
ssl_client_certificate '${SSL_CLIENT_CERTIFICATE}' # e.g. ssl_client_certificate /etc/ssl/rootca-cert.pem;
ssl_verify_client optional;
ssl_verify_depth 2;
# This example allows access to all three TLP locations for all certs.
location ~ /.well-known/csaf/(red|green|amber)/{
autoindex on;
# in this location access is only allowed with client certs
if ($ssl_client_verify != SUCCESS){
# we use status code 404 == "Not Found", because we do not
# want to reveal if this location exists or not.
return 404;
}
}
``` ```
server { <!-- MARKDOWN-AUTO-DOCS:END -->
# Other Config
# ...
ssl_client_certificate /etc/ssl/rootca-cert.pem;
ssl_verify_client optional;
ssl_verify_depth 2;
# This example allows access to all three TLP locations for all certs.
location ~ /.well-known/csaf/(red|green|amber)/{
autoindex on;
# in this location access is only allowed with client certs
if ($ssl_client_verify != SUCCESS){
# we use status code 404 == "Not Found", because we do not
# want to reveal if this location exists or not.
return 404;
}
}
}
```
This will restrict the access to the defined paths in the ```location``` This will restrict the access to the defined paths in the ```location```
directive to only authenticated client certificates issued by the CAs directive to only authenticated client certificates issued by the CAs
which are configured with `ssl_client_certificate`. which are configured with `ssl_client_certificate`.
@ -47,6 +47,6 @@ To test this see [development-client-certs.md](development-client-certs.md) and
* From the browser after importing the `testclient1.p12`: * From the browser after importing the `testclient1.p12`:
nagivate to the protected directories. nagivate to the protected directories.
* With curl: `curl https://{serverURL}/.well-known/csaf/red/ --cert-type p12 --cert testclient1.p12`. * With curl: `curl https://{serverURL}/.well-known/csaf/red/ --cert-type p12 --cert testclient1.p12`.
(If the server uses self-signed certifcate one of the following options should be added to the `curl` command: (If the server uses a root certifcate that is not in the default certificate store one of the following options should be added to the `curl` command:
`--insecure` to disable the verification, * `--insecure` to disable the verification,
`--cacert {CA-Certificate-File}` to pass the CA-Certificate that verifies the server). * `--cacert {CA-Certificate-File}` to pass the CA-Certificate that verifies the server).

View file

@ -11,14 +11,16 @@ which is suitable for testing in development setups.
## create root CA ## create root CA
```bash <!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/createRootCAForITest.sh&lines=13-50) -->
mkdir devca1 <!-- The below code snippet is automatically added from ../docs/scripts/createRootCAForITest.sh -->
cd devca1 ```sh
mkdir -p ~/${FOLDERNAME}
cd ~/${FOLDERNAME}
certtool --generate-privkey --outfile rootca-key.pem certtool --generate-privkey --outfile rootca-key.pem
echo ' echo '
organization = "CSAF Tools Development (internal)" organization = "'${ORGANAME}'"
country = DE country = DE
cn = "Tester" cn = "Tester"
@ -30,19 +32,21 @@ serial = 001
expiration_days = 100 expiration_days = 100
' >gnutls-certtool.rootca.template ' >gnutls-certtool.rootca.template
certtool --generate-self-signed --load-privkey rootca-key.pem --outfile rootca-cert.pem --template gnutls-certtool.rootca.template certtool --generate-self-signed --load-privkey rootca-key.pem --outfile rootca-cert.pem --template gnutls-certtool.rootca.template --stdout | head -1
``` ```
<!-- MARKDOWN-AUTO-DOCS:END -->
## create webserver cert ## create webserver cert
```bash <!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/createWebserverCertForITest.sh&lines=11-55) -->
#being in devca1/ <!-- The below code snippet is automatically added from ../docs/scripts/createWebserverCertForITest.sh -->
```sh
cd ~/${FOLDERNAME}
certtool --generate-privkey --outfile testserver-key.pem certtool --generate-privkey --outfile testserver-key.pem
echo ' echo '
organization = "CSAF Tools Development (internal)" organization = "'${ORGANAME}'"
country = DE country = DE
cn = "Service Testing" cn = "Service Testing"
@ -58,14 +62,20 @@ serial = 010
expiration_days = 50 expiration_days = 50
' > gnutls-certtool.testserver.template ' > gnutls-certtool.testserver.template
certtool --generate-certificate --load-privkey testserver-key.pem --outfile testserver.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testserver.template certtool --generate-certificate --load-privkey testserver-key.pem --outfile testserver.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testserver.template --stdout | head -1
cat testserver.crt rootca-cert.pem >bundle.crt cat testserver.crt rootca-cert.pem >bundle.crt
echo Full path config options for nginx:
echo " ssl_certificate \"$PWD/bundle.crt\";"
echo " ssl_certificate_key \"$PWD/testserver-key.pem\";"
```
SSL_CERTIFICATE=$(
echo "$PWD/bundle.crt;"
)
SSL_CERTIFICATE_KEY=$(
echo "$PWD/testserver-key.pem;"
)
```
<!-- MARKDOWN-AUTO-DOCS:END -->
Replace `{FOLDERNAME}` with the folder name you want to save the keys into it and `{ORGANAME}` with the organisation name that should be used by creating the Certificate.
## Considerations and References ## Considerations and References

View file

@ -10,13 +10,15 @@ would used for server and for client certificates.)
The following lines directly create the client certificate. The following lines directly create the client certificate.
(As opposed to first creating a certificate signing request and (As opposed to first creating a certificate signing request and
then signing it.) then signing it.)
<!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/createCCForITest.sh&lines=15-35) -->
<!-- The below code snippet is automatically added from ../docs/scripts/createCCForITest.sh -->
```sh
cd ~/${FOLDERNAME}
```bash
# being in devca1/
certtool --generate-privkey --outfile testclient1-key.pem certtool --generate-privkey --outfile testclient1-key.pem
echo ' echo '
organization = "CSAF Tools Development (internal)" organization = "'${ORGANAME}'"
country = DE country = DE
cn = "TLS Test Client 1" cn = "TLS Test Client 1"
@ -28,18 +30,23 @@ serial = 020
expiration_days = 50 expiration_days = 50
' > gnutls-certtool.testclient1.template ' > gnutls-certtool.testclient1.template
certtool --generate-certificate --load-privkey testclient1-key.pem --outfile testclient1.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testclient1.template certtool --generate-certificate --load-privkey testclient1-key.pem --outfile testclient1.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testclient1.template --stdout | head -1
certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient1.crt --load-privkey testclient1-key.pem --to-p12 --p12-name "Test Client 1" --null-password --outder --outfile testclient1.p12 certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient1.crt --load-privkey testclient1-key.pem --to-p12 --p12-name "Test Client 1" --null-password --outder --outfile testclient1.p12
``` ```
<!-- MARKDOWN-AUTO-DOCS:END -->
and we do a second one with shorter expiration day: and we do a second one with shorter expiration day:
```bash <!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/createCCForITest.sh&lines=34-53) -->
<!-- The below code snippet is automatically added from ../docs/scripts/createCCForITest.sh -->
```sh
certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient1.crt --load-privkey testclient1-key.pem --to-p12 --p12-name "Test Client 1" --null-password --outder --outfile testclient1.p12
certtool --generate-privkey --outfile testclient2-key.pem certtool --generate-privkey --outfile testclient2-key.pem
echo ' echo '
organization = "CSAF Tools Development (internal)" organization = "'${ORGANAME}'"
country = DE country = DE
cn = "TLS Test Client 2" cn = "TLS Test Client 2"
@ -51,13 +58,12 @@ serial = 021
expiration_days = 1 expiration_days = 1
' > gnutls-certtool.testclient2.template ' > gnutls-certtool.testclient2.template
certtool --generate-certificate --load-privkey testclient2-key.pem --outfile testclient2.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testclient2.template certtool --generate-certificate --load-privkey testclient2-key.pem --outfile testclient2.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testclient2.template --stdout | head -1
certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient2.crt --load-privkey testclient2-key.pem --to-p12 --p12-name "Test Client 2" --null-password --outder --outfile testclient2.p12 certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient2.crt --load-privkey testclient2-key.pem --to-p12 --p12-name "Test Client 2" --null-password --outder --outfile testclient2.p12
``` ```
<!-- MARKDOWN-AUTO-DOCS:END -->
In case of many CAs are used to verify the client certificates these should be included in the list of the allowed CA certificates in the `ssl_client_certificate` bundle of nginx. In case of many CAs are used to verify the client certificates these should be included in the list of the allowed CA certificates in the `ssl_client_certificate` bundle of nginx.
E.g. `cat rootca-cert-1.pem rootca-cert-2.pem >> allowedCAs.pem`. Nginx config: `ssl_client_certificate allowedCAs.pem;` E.g. `cat rootca-cert-1.pem rootca-cert-2.pem >> allowedCAs.pem`. Nginx config: `ssl_client_certificate allowedCAs.pem;`

View file

@ -44,25 +44,21 @@ We recommend to
### Example configuration ### Example configuration
Assuming the relevant server block is in `/etc/nginx/sites-enabled/default`, Assuming the relevant server block is in `/etc/nginx/sites-enabled/default`,
change the `listen` configuration and add options so nginx change the `listen` configuration in the `server {}` block and add options so nginx
finds your your private key and the certificate chain. finds your your private key and the certificate chain.
```nginx <!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/TLSConfigsForITest.sh&lines=31-37) -->
server { <!-- The below code snippet is automatically added from ../docs/scripts/TLSConfigsForITest.sh -->
listen 443 ssl http2 default_server; # ipv4 ```sh
listen [::]:443 ssl http2 default_server; # ipv6 listen 443 ssl default_server; # ipv4
server_name www.example.com listen [::]:443 ssl http2 default_server; # ipv6
ssl_certificate /etc/ssl/{domainName}.pem; # or bundle.crt ssl_certificate '${SSL_CERTIFICATE}' # e.g. ssl_certificate /etc/ssl/csaf/bundle.crt
ssl_certificate_key /etc/ssl/{domainName}.key"; ssl_certificate_key '${SSL_CERTIFICATE_KEY}' # e.g. ssl_certificate_key /etc/ssl/csaf/testserver-key.pem;
ssl_protocols TLSv1.2 TLSv1.3; ssl_protocols TLSv1.2 TLSv1.3;
# Other Config
# ...
}
``` ```
<!-- MARKDOWN-AUTO-DOCS:END -->
Replace `{domainName}` with the name for your certificate in the example.
Reload or restart nginx to apply the changes (e.g. `systemctl reload nginx` Reload or restart nginx to apply the changes (e.g. `systemctl reload nginx`
on Debian or Ubuntu.) on Debian or Ubuntu.)

View file

@ -24,7 +24,9 @@ chmod -R g+w .
Modify the content of `/etc/nginx/fcgiwrap.conf` like following: Modify the content of `/etc/nginx/fcgiwrap.conf` like following:
``` <!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/setupProviderForITest.sh&lines=24-52) -->
<!-- The below code snippet is automatically added from ../docs/scripts/setupProviderForITest.sh -->
```sh
# Include this file on your nginx.conf to support debian cgi-bin scripts using # Include this file on your nginx.conf to support debian cgi-bin scripts using
# fcgiwrap # fcgiwrap
location /cgi-bin/ { location /cgi-bin/ {
@ -55,7 +57,7 @@ location /cgi-bin/ {
fastcgi_param SSL_CLIENT_I_DN $ssl_client_i_dn; fastcgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
} }
``` ```
<!-- MARKDOWN-AUTO-DOCS:END -->
Add to `/etc/nginx/sites-enabled/default`: Add to `/etc/nginx/sites-enabled/default`:
``` ```
@ -89,28 +91,32 @@ Rename and place the `csaf_provider` binary file under `/usr/lib/cgi-bin/csaf_pr
Create configuration file under `/usr/lib/csaf/config.toml`: Create configuration file under `/usr/lib/csaf/config.toml`:
``` <!-- MARKDOWN-AUTO-DOCS:START (CODE:src=../docs/scripts/setupProviderForITest.sh&lines=82-87) -->
<!-- The below code snippet is automatically added from ../docs/scripts/setupProviderForITest.sh -->
```sh
# upload_signature = true # upload_signature = true
# key = "/usr/lib/csaf/public.asc" # key = "/usr/lib/csaf/public.asc"
key = "/usr/lib/csaf/private.asc" key = "/usr/lib/csaf/private.asc"
#tlps = ["green", "red"] #tlps = ["green", "red"]
canonical_url_prefix = "http://192.168.56.102" canonical_url_prefix = "https://localhost:8443"
#no_passphrase = true #no_passphrase = true
``` ```
with suitable replacements <!-- MARKDOWN-AUTO-DOCS:END -->
(This configurations-example assumes that the private/public keys are available under `/usr/lib/csaf/`). with suitable [replacements](#provider-options)
(This configuration examples assumes that the private/public keys are available under `/usr/lib/csaf/`).
with suitable [replacements](#provider-options).
Create the folders: Create the folders:
```(shell) ```(shell)
curl http://192.168.56.102/cgi-bin/csaf_provider.go/create curl https://192.168.56.102/cgi-bin/csaf_provider.go/create --cert-type p12 --cert {clientCertificatfile}
``` ```
Replace {clientCertificate} with the client certificate file.
Or using the uploader: Or using the uploader:
```(shell) ```(shell)
./csaf_uploader -a create -u http://192.168.56.102/cgi-bin/csaf_provider.go ./csaf_uploader -a create -u http://192.168.56.102/cgi-bin/csaf_provider.go -p {password}
``` ```
Replace {password} with the password used for the authentication with csaf_provider.
This needs to set the `password` option in `config.toml`.
## Provider options ## Provider options
Provider has many config options described as following: Provider has many config options described as following:

25
docs/scripts/Readme.md Normal file
View file

@ -0,0 +1,25 @@
Scripts for assisting the Integration tests. They are written on Ubuntu 20.04 TLS amd64.
- `prepareUbunutForITest.sh` installs the required packages for the csaf_distribution integration tests on a naked ubuntu 20.04 LTS amd64.
- `TLSConfigsForITest.sh` generates a root CA and webserver cert by running `createRootCAForITest.sh` and `createWebserverCertForITest.sh`
and configures nginx for serving TLS connections.
- `TLSClientConfigsForITest.sh` generates client certificates by calling `createCCForITest.sh` which uses the root certificate initialized before with `createRootCAForITest.sh`. It configures nginx to enable the authentication with client certificate. (This assumes that the same folder name is used to create the root certificate)
- `setupProviderForITest.sh` builds the csaf_provider, writes the required nginx configurations and create the initial folders. IT calls `uploadToProvider.sh` to upload some csaf example files to the provider.
As creating the folders needs to authenticate with the csaf_provider, the configurations of TLS server and Client certificate authentication should be set. So it is recommended to call the scripts in this order: `TLSConfigsForITest.sh`, `TLSClientConfigsForITest.sh`, `setupProviderForITest.sh`
Calling example (as root):
``` bash
curl --fail -O https://raw.githubusercontent.com/csaf-poc/csaf_distribution/main/docs/scripts/prepareUbuntuInstanceForITests.sh
bash prepareUbuntuInstanceForITests.sh
git clone https://github.com/csaf-poc/csaf_distribution.git
pushd csaf_distribution/docs/scripts/
env FOLDERNAME=devca1 ORGANAME="CSAF Tools Development (internal)" ./TLSConfigsForITest.sh
env FOLDERNAME=devca1 ORGANAME="CSAF Tools Development (internal)" ./TLSClientConfigsForITest.sh
./setupProviderForITest.sh
```

View file

@ -0,0 +1,45 @@
#!/usr/bin/env bash
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
# It sets the right nginx configurations for enabling client certificate authentication.
# FOLDERNAME and ORGANAME variables must be set.
# FOLDERNAME: Where to store the CAs and keys.
# ORGANAME: The organization name used in the CA template.
# Usage Example: env FOLDERNAME=devca1 ORGANAME="CSAF Tools Development (internal)" ./TLSClientConfigsForITest.sh
set -e
NGINX_CONFIG_PATH=/etc/nginx/sites-available/default
cd ~/csaf_distribution/docs/scripts/
source ./createCCForITest.sh
echo '
ssl_client_certificate '${SSL_CLIENT_CERTIFICATE}' # e.g. ssl_client_certificate /etc/ssl/rootca-cert.pem;
ssl_verify_client optional;
ssl_verify_depth 2;
# This example allows access to all three TLP locations for all certs.
location ~ /.well-known/csaf/(red|green|amber)/{
autoindex on;
# in this location access is only allowed with client certs
if ($ssl_client_verify != SUCCESS){
# we use status code 404 == "Not Found", because we do not
# want to reveal if this location exists or not.
return 404;
}
}
'> clientCertificateConfigs.txt
sed -i "/^server {/r ${HOME}/${FOLDERNAME}/clientCertificateConfigs.txt" $NGINX_CONFIG_PATH
systemctl reload nginx

View file

@ -0,0 +1,52 @@
#!/usr/bin/env bash
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
# This script generates webserver cert that is signed with the generated root CA.
# It sets the right nginx configurations for serving TLS connections.
# FOLDERNAME and ORGANAME variables must be set.
# FOLDERNAME: Where to store the CAs and keys.
# ORGANAME: The organization name used in the CA template.
# Usage Example: env FOLDERNAME=devca1 ORGANAME="CSAF Tools Development (internal)" ./TLSConfigsForITest.sh
set -e
NGINX_CONFIG_PATH=/etc/nginx/sites-available/default
cd ~/csaf_distribution/docs/scripts/
## Create Root CA
./createRootCAForITest.sh
## Create webserver cert
source ./createWebserverCertForITest.sh
# Configure nginx
echo '
listen 443 ssl default_server; # ipv4
listen [::]:443 ssl http2 default_server; # ipv6
ssl_certificate '${SSL_CERTIFICATE}' # e.g. ssl_certificate /etc/ssl/csaf/bundle.crt
ssl_certificate_key '${SSL_CERTIFICATE_KEY}' # e.g. ssl_certificate_key /etc/ssl/csaf/testserver-key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
' > TLSConfigs.txt
# a second listener port for testing setup where someone wants to tunnel access
# to an unpriviledged port and still have the same access url
echo '
listen 8443 ssl default_server; # ipv4
listen [::]:8443 ssl http2 default_server; # ipv6
' > TLS8443Configs.txt
cp $NGINX_CONFIG_PATH $NGINX_CONFIG_PATH.org
sed -i "/^server {/r ${HOME}/${FOLDERNAME}/TLSConfigs.txt" $NGINX_CONFIG_PATH
sed -i "/^server {/r ${HOME}/${FOLDERNAME}/TLS8443Configs.txt" $NGINX_CONFIG_PATH
sed -i "/^\s*listen.*80/d" $NGINX_CONFIG_PATH # Remove configs for listinig on port 80
systemctl reload nginx

View file

@ -0,0 +1,57 @@
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
# This scripts creates two client certificates. It uses for signing the root certifcate
# created with `createRootCAForITest.sh` that must be run earlier.
set -e
mkdir -p ~/${FOLDERNAME}
cd ~/${FOLDERNAME}
certtool --generate-privkey --outfile testclient1-key.pem
echo '
organization = "'${ORGANAME}'"
country = DE
cn = "TLS Test Client 1"
tls_www_client
signing_key
encryption_key
serial = 020
expiration_days = 50
' > gnutls-certtool.testclient1.template
certtool --generate-certificate --load-privkey testclient1-key.pem --outfile testclient1.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testclient1.template --stdout | head -1
certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient1.crt --load-privkey testclient1-key.pem --to-p12 --p12-name "Test Client 1" --null-password --outder --outfile testclient1.p12
certtool --generate-privkey --outfile testclient2-key.pem
echo '
organization = "'${ORGANAME}'"
country = DE
cn = "TLS Test Client 2"
tls_www_client
signing_key
encryption_key
serial = 021
expiration_days = 1
' > gnutls-certtool.testclient2.template
certtool --generate-certificate --load-privkey testclient2-key.pem --outfile testclient2.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testclient2.template --stdout | head -1
certtool --load-ca-certificate rootca-cert.pem --load-certificate testclient2.crt --load-privkey testclient2-key.pem --to-p12 --p12-name "Test Client 2" --null-password --outder --outfile testclient2.p12
SSL_CLIENT_CERTIFICATE=$(
echo "$PWD/rootca-cert.pem;"
)

View file

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
set -e
mkdir -p ~/${FOLDERNAME}
cd ~/${FOLDERNAME}
certtool --generate-privkey --outfile rootca-key.pem
echo '
organization = "'${ORGANAME}'"
country = DE
cn = "Tester"
ca
cert_signing_key
crl_signing_key
serial = 001
expiration_days = 100
' >gnutls-certtool.rootca.template
certtool --generate-self-signed --load-privkey rootca-key.pem --outfile rootca-cert.pem --template gnutls-certtool.rootca.template --stdout | head -1

View file

@ -0,0 +1,41 @@
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
set -e
cd ~/${FOLDERNAME}
certtool --generate-privkey --outfile testserver-key.pem
echo '
organization = "'${ORGANAME}'"
country = DE
cn = "Service Testing"
tls_www_server
signing_key
encryption_key
non_repudiation
dns_name = "*.local"
dns_name = "localhost"
serial = 010
expiration_days = 50
' > gnutls-certtool.testserver.template
certtool --generate-certificate --load-privkey testserver-key.pem --outfile testserver.crt --load-ca-certificate rootca-cert.pem --load-ca-privkey rootca-key.pem --template gnutls-certtool.testserver.template --stdout | head -1
cat testserver.crt rootca-cert.pem >bundle.crt
SSL_CERTIFICATE=$(
echo "$PWD/bundle.crt;"
)
SSL_CERTIFICATE_KEY=$(
echo "$PWD/testserver-key.pem;"
)

View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
#
# Desc: Tries getting csaf 2.0 examples from api.github. Do not run too often!
#
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
set -e
# using an extended regular expression to whitelist only CSAF 2.0 filenames
# with a sane path
CSAFPATHregexp='^ *"path": "(csaf_2.0/examples/csaf/[a-z0-9+-_]+.json)",'
curl --silent --show-error -H 'Accept: application/vnd.github.v3.raw' \
https://api.github.com/repos/oasis-tcs/csaf/contents/csaf_2.0/examples/csaf \
| grep -E "$CSAFPATHregexp" \
| sed -E -e "s;${CSAFPATHregexp};\1;" \
> csaf_examples_pathnames.txt
mkdir csaf_examples
cd csaf_examples
cat ../csaf_examples_pathnames.txt | \
xargs -I {} \
curl --silent --show-error -H 'Accept: application/vnd.github.v3.raw' \
https://api.github.com/repos/oasis-tcs/csaf/contents/{} -O

View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e
# This script prepares a naked Ubuntu 20.04 LTS amd64
# for the csaf_distribution integration tests
# by installing the required packages.
apt install -y make git nginx fcgiwrap gnutls-bin
# Install Go from binary distribution
curl -O https://storage.googleapis.com/golang/go1.18.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.18.linux-amd64.tar.gz

View file

@ -0,0 +1,96 @@
#!/usr/bin/env bash
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
# This script sets up the csaf_provider and writes the required nginx configurations.
# It creates the initial folders and uploads some example files to the csaf_provider with the help of `uploadToProvider.sh`
set -e
chgrp -R www-data /var/www
chmod -R g+w /var/www
NGINX_CONFIG_PATH=/etc/nginx/sites-available/default
cp /usr/share/doc/fcgiwrap/examples/nginx.conf /etc/nginx/fcgiwrap.conf
echo '
# Include this file on your nginx.conf to support debian cgi-bin scripts using
# fcgiwrap
location /cgi-bin/ {
# Disable gzip (it makes scripts feel slower since they have to complete
# before getting gzipped)
gzip off;
# Set the root to /usr/lib (inside this location this means that we are
# giving access to the files under /usr/lib/cgi-bin)
root /usr/lib;
# Fastcgi socket
fastcgi_pass unix:/var/run/fcgiwrap.socket;
# Fastcgi parameters, include the standard ones
include /etc/nginx/fastcgi_params;
fastcgi_split_path_info ^(.+\.go)(.*)$;
# Adjust non standard parameters (SCRIPT_FILENAME)
fastcgi_param SCRIPT_FILENAME /usr/lib$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param CSAF_CONFIG /usr/lib/csaf/config.toml;
fastcgi_param SSL_CLIENT_VERIFY $ssl_client_verify;
fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
fastcgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
}
' > /etc/nginx/fcgiwrap.conf
sed -i "/^server {/a include fcgiwrap.conf;" $NGINX_CONFIG_PATH
echo "
# For atomic directory switches
disable_symlinks off;
# directory listings
autoindex on;
" > locationConfig.txt
sed -i "/^\s*location \/ {/r locationConfig.txt" $NGINX_CONFIG_PATH # Insert config inside location{}
systemctl reload nginx
# assuming that we are in a checked out version in the docs/scripts directory
# and we want to build the version that is currently checked out
pushd ../..
export PATH=$PATH:/usr/local/go/bin
make build_linux
# Place the binary under the corresponding path.
mkdir -p /usr/lib/cgi-bin/
cp bin-linux-amd64/csaf_provider /usr/lib/cgi-bin/csaf_provider.go
mkdir -p /usr/lib/csaf/
cp docs/test-keys/*.asc /usr/lib/csaf/
# Configuration file
echo '
# upload_signature = true
# key = "/usr/lib/csaf/public.asc"
key = "/usr/lib/csaf/private.asc"
#tlps = ["green", "red"]
canonical_url_prefix = "https://localhost:8443"
#no_passphrase = true
' > /usr/lib/csaf/config.toml
# Create the Folders
curl https://localhost:8443/cgi-bin/csaf_provider.go/create --cert-type p12 --cert ~/devca1/testclient1.p12 --insecure
popd
# Upload files
./uploadToProvider.sh

View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
#
# Desc: Call ./downloadExamples.sh and then try csaf_uploader.
#
# This file is Free Software under the MIT License
# without warranty, see README.md and LICENSES/MIT.txt for details.
#
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: 2022 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
# Software-Engineering: 2022 Intevation GmbH <https://intevation.de>
set -e
# assumes that the following script only downloads file with filenames
# following https://docs.oasis-open.org/csaf/csaf/v2.0/cs01/csaf-v2.0-cs01.html#51-filename
# which are save to process further
./downloadExamples.sh
TLPs=("white" "green" "amber" "red")
COUNTER=0
for f in $(ls csaf_examples);
do
../../bin-linux-amd64/csaf_uploader -a upload -t ${TLPs[$COUNTER]} \
-u https://localhost:8443/cgi-bin/csaf_provider.go --insecure -P security123 \
--client-cert ~/devca1/testclient1.crt --client-key ~/devca1/testclient1-key.pem \
./csaf_examples/"$f";
let COUNTER++
done;

23
docs/test-keys/Readme.md Normal file
View file

@ -0,0 +1,23 @@
OpenPGP key-pair for testing.
This has been created with:
* gpg (GnuPG) 2.2.19
* (linked with) libgcrypt 1.8.5
### `test1@example.com`
```bash
gpg --full-gen-key
RSA (sign only)
Requested keysize is 4096 bits
key does not expire at all
Real name: test1
Email address: test1@example.com
comment:
```
```bash
gpg --export-secret-key --armor test1 > private.asc
gpg --export --armor test1 > public.asc
```
The passphrase for this test OpenPGP key-pair is: `security123`

View file

@ -0,0 +1,56 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
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
=ssfC
-----END PGP PRIVATE KEY BLOCK-----

28
docs/test-keys/public.asc Normal file
View file

@ -0,0 +1,28 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGI8XxwBEACaVzxyaHp6+D+cO6bNkIQlnX3gmQn5fXeaLF7nwmtYr1c2bAsn
x2SNwrqKIWb80VqPbqO3L+i742IIYF5yS5W/UDaKOFSDqjZsSIleb/gH83Wcnahm
UWxi7ENiHQTSGMG7MWb+uU11TUBhxHsW01oGID06dCz/0PmkkuuggSli3sulM9B7
UKAqZO2uvGEb3/n2rrEfc8Nh5XgrfbV4f1Gqfxsn1kFr8hIdbfoRuJ98jJ771a4M
eOYurY5EyT/IhFPN+f4sGeztcPtENJIww5wJCzmw5KEPtyTBH97QSUjSsmqGhojk
YpL5yAHId4xGGU717pgxLONS1yjW4r5ydjcUN4xRJLJVb6LB3/3YXcaVhVPXaDM7
uC97O7CWzlrppACAXMLvsR/flvCskRWAnZ2PKP899Yq3FYZggKC5uvOQbdL3Ya3R
JjI0hRcVRG3by6flRzyfHkz68bsDX5vCCA1NA56JSquCgWDhaORVCE9gVy1KE8ap
h2rgsHwjtde+1wuRDY0FhqFAraWpyxJRT+xCSFozRZxCtBdhAgLnK07ovIUU3aOv
xRpKyUSjw+zVx437S3U8al/hjttgK1KtCt9F5i4nhyXTM+K6FnIHzQsl1OdRNbqA
cmxW1hDmedVOrJwq5VWqquxlf430HrRU9UQGGn1YcGg3rtyLqut63hZvQQARAQAB
tBl0ZXN0MSA8dGVzdDFAZXhhbXBsZS5jb20+iQJOBBMBCgA4FiEEOVOfoEE9nJwJ
7hauNkDK3qAbSi8FAmI8XxwCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ
NkDK3qAbSi8GCQ//SdBBEq7uGHFb5YrNKB9cfGTWgM5cUJRz2I9OaXnDAJDleDED
c/bB3rubSJTAaCj8O0obC9kvKWGzQ89TG064pAC+sQWfnwTvNR3uQyR6050xA1cW
SsWloBICNpwN/oRk4QtUyvy0HIDV/UCe5AgJsR/Y/FnpFv/VJDVfQeckDYdAljqW
b5IQsu1PGTXNzJi1/boMX4NqK/vkSMujIOqXONz7fRhl+Kht8aum1MYZZD2snHG1
qXoqlUZkDEsbrDPvOds7Pu0DTNpTvBcEFh5apvZW8EtgTBom3/0n4dGxetvXzqVM
sZcToFWEeieYCkXlFOICQT7HSXo06z9pbVncg5IH3ytVaINGxve9ACpwOeIXClur
8U5eRBd3m8KEi/jHYGBQHOO4yUgUDX9YhoabLOvPTD4AsV7FlisqS8GW2YAa+nGK
qyDDIIZtMiG2r1Gd/zdKrjAJZZu1Z1Zt5tphwbxWFRkxFDB8pszo/JXeuyLevBUK
JrsfXjPJLtpTvIrxnUogJvVdF0fmlLJu2FI/71oPrEiyVytH4JpQv44r5jJ6NDH+
/KSqoF/dzuZIHI7CTTYUNZTDWJryjfc3dZ4pzgloWvotVfZUBwyrLwko+uOblb84
kSxNqYxdYAjkVFBpr2xEdjhtQg/44MQpImvoWLyXVUt3hFtSOdWZEURcMOk=
=4s3V
-----END PGP PUBLIC KEY BLOCK-----