#!/usr/bin/env bash # Restconf+NACM openssl functionality using server and client certs # The test creates certs and keys: # A CA, server key/cert, user key/cert for two users # Can we try illegal certs? # Magic line must be first in script (see README.md) s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi # Only works with evhtp and https if [ "${WITH_RESTCONF}" != "evhtp" ]; then if [ "$s" = $0 ]; then exit 0; else return 0; fi # skip fi RCPROTO=https APPNAME=example # Common NACM scripts . ./nacm.sh fyang=$dir/example.yang cfg=$dir/conf.xml # Local for test here certdir=$dir/certs srvkey=$certdir/srv_key.pem srvcert=$certdir/srv_cert.pem cakey=$certdir/ca_key.pem # needed? cacert=$certdir/ca_cert.pem users="andy guest" # generate certs for some users in nacm.sh xusers="limited" # Set invalid cert # Whether to generate new keys or not (only if $dir is not removed) # Here dont generate keys if restconf started stand-alone (RC=0) : ${genkeys:=true} #if [ $RC -eq 0 ]; then # genkeys=false #fi test -d $certdir || mkdir $certdir # Use yang in example cat < $fyang module example{ yang-version 1.1; namespace "urn:example:example"; prefix ex; import ietf-netconf-acm { prefix nacm; } leaf x{ type int32; description "something to edit"; } } EOF # Two groups: admin allow all, guest allow nothing RULES=$(cat < false permit deny deny $NGROUPS guest-acl guest deny-ncm * * deny Do not allow guests any access to the NETCONF $NADMIN 0 EOF ) if $genkeys; then # Server certs . ./certs.sh # create client certs for name in $users $xusers; do cat< $dir/$name.cnf [req] prompt = no distinguished_name = dn [dn] CN = $name # This can be verified using SSL_set1_host emailAddress = $name@foo.bar O = Clixon L = Stockholm C = SE EOF # Create client key openssl genrsa -out "$certdir/$name.key" 2048 # Generate CSR (signing request) openssl req -new -config $dir/$name.cnf -key $certdir/$name.key -out $certdir/$name.csr # Sign by CA openssl x509 -req -extfile $dir/$name.cnf -days 1 -passin "pass:password" -in $certdir/$name.csr -CA $cacert -CAkey $cakey -CAcreateserial -out $certdir/$name.crt done # client key # invalid for name in $xusers; do openssl x509 -req -extfile $dir/$name.cnf -days 0 -passin "pass:password" -in $certdir/$name.csr -CA $cacert -CAkey $cakey -CAcreateserial -out $certdir/$name.crt done # invalid fi # genkeys # Write local config cat < $cfg $cfg ietf-netconf:startup /usr/local/share/clixon $IETFRFC $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/backend example_backend.so$ /usr/local/lib/$APPNAME/restconf /usr/local/lib/$APPNAME/cli $APPNAME /usr/local/var/$APPNAME/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile $dir true internal true client-certificate $srvcert $srvkey $cacert $DBG false default
0.0.0.0
443 true
EOF # Run The test, ssl config is in local config function testrun() { cat < $dir/startup_db <${DATASTORE_TOP}> $RULES EOF if [ $BE -ne 0 ]; then new "kill old backend" sudo clixon_backend -zf $cfg if [ $? -ne 0 ]; then err fi sudo pkill -f clixon_backend # to be sure new "start backend -s startup -f $cfg" start_backend -s startup -f $cfg fi new "wait for backend" wait_backend if [ $RC -ne 0 ]; then new "kill old restconf daemon" stop_restconf_pre new "start restconf daemon -s -c" start_restconf -f $cfg fi new "wait for restconf" wait_restconf --key $certdir/andy.key --cert $certdir/andy.crt new "enable nacm" expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X PUT -H "Content-Type: application/yang-data+json" -d '{"ietf-netconf-acm:enable-nacm": true}' $RCPROTO://localhost/restconf/data/ietf-netconf-acm:nacm/enable-nacm)" 0 "HTTP/1.1 204 No Content" new "admin get x" expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":0}' new "guest get x" expectpart "$(curl $CURLOPTS --key $certdir/guest.key --cert $certdir/guest.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 403 Forbidden" '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"access-denied","error-severity":"error","error-message":"access denied"}}}' new "admin set x 42" expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X PUT -H "Content-Type: application/yang-data+json" -d '{"example:x":42}' $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 204 No Content" new "admin get x 42" expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}' # Negative tests new "Unknown yyy no cert get x 42" echo "dummy" > $certdir/yyy.key echo "dummy" > $certdir/yyy.crt expectpart "$(curl $CURLOPTS --key $certdir/yyy.key --cert $certdir/yyy.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 58 " could not load PEM client certificate" # See (3) client-cert is NULL in restconf_main_openssl.c new "No cert: certificate required" expectpart "$(curl $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" 0 "HTTP/1.1 400 Bad Request" new "limited invalid cert" expectpart "$(curl $CURLOPTS --key $certdir/limited.key --cert $certdir/limited.crt -X GET $RCPROTO://localhost/restconf/data/example:x 2>&1)" "35 55 56" # 55 "certificate expired" # Just ensure all is OK new "admin get x 42" expectpart "$(curl $CURLOPTS --key $certdir/andy.key --cert $certdir/andy.crt -X GET $RCPROTO://localhost/restconf/data/example:x)" 0 "HTTP/1.1 200 OK" '{"example:x":42}' if [ $RC -ne 0 ]; then new "Kill restconf daemon" stop_restconf fi if [ $BE -ne 0 ]; then new "Kill backend" # Check if premature kill pid=$(pgrep -u root -f clixon_backend) if [ -z "$pid" ]; then err "backend already dead" fi # kill backend stop_backend -f $cfg fi } new "Run test" testrun rm -rf $dir # unset conditional parameters unset RCPROTO endtest