diff --git a/warden3/contrib/warden_ra/README b/warden3/contrib/warden_ra/README
new file mode 100644
index 0000000000000000000000000000000000000000..9f6789f575960bd9bdc4661abc3c8039dd9c227c
--- /dev/null
+++ b/warden3/contrib/warden_ra/README
@@ -0,0 +1,233 @@
+Warden Registration Authority for Warden 3.X
+============================================
+
+Introduction
+------------
+
+Warden RA is a certificate registration authority for Warden_ server.
+It is meant to support the client registration process and simplification
+of the credential transport.
+
+As Warden clients are authenticated by X509 certificate, the usual certificate
+generation process can be used - local key and certificate request gets
+generated, the request is submitted to registration authority, and after
+review, certificate is issued and delivered back.
+
+However in centralised Warden setup, it is useful to be able to preallow
+certificate for particular client during negotiation phase (thus removing
+another round-trip).
+
+This is done by issuing 'token' by Warden registration officer during client
+registration, which is just a oneshot password, allowing sending the request
+and getting new certificate in one step through web API.
+
+Password is meant only for completely new clients or unusual situations,
+however RA also allows prolongation - generating new certificate by using
+old certificate (which must be still valid, of course) instead of password.
+
+The application script, which can be distributed to newly registered clients,
+is also included.
+
+Dependencies
+------------
+
+ 1. Platform
+
+    Python 2.7+
+    Apache 2.2+
+    mod_wsgi 3.3+
+    EJBCA_ 3.9+
+
+
+Registration process
+--------------------
+
+New client credentials
+``````````````````````
+
+After succesful negotiation of new Warden client parameters, the registration
+officer enables new certificate generation by issuing (on the server side):
+
+    warden_ra.py applicant --name org.example.warden.client
+
+The tool generates and sets one time password on the registration authority
+side, and this password can be sent (preferably through the secured channel)
+to the new client administrator along with other setup information.
+
+The client administrator runs the application script with application
+password:
+
+    warden_apply.sh org.example.warden.client P4SSW0RD
+
+The script creates new X509 key, CSR certificate request and makes call to
+the Warden RA web service, where it obtains the new complete certificate.
+
+
+Prolonging existing client credentials
+``````````````````````````````````````
+
+The client administrator runs the application script with his existing valid
+Warden credentials, which he needs to prolong:
+
+    warden_apply.sh org.example.warden.client cert.pem key.pem
+
+The script creates new X509 key, CSR certificate request and makes call to
+the Warden RA web service, where it obtains the new complete certificate.
+
+
+Installation
+------------
+
+As for now, correctly configured and running EJBCA_ PKI is necessary. PKI part
+of the RA is however pluggable, so simple openssl backend is also planned.
+
+
+This depends heavily on your distribution and Apache configuration.
+Basically you need to create and include apache.conf:
+
+  Include /opt/warden_ra/apache22.conf
+
+or paste the contents into whichever Directory, Location or VirtualHost
+you dedicate for Warden RA. Note that you have to use different host than
+the one for Warden server, as Warden RA needs different Apache options
+for SSL authentication.
+
+You may need to change paths to certificate/key/ca material, path to
+warden_server.wsgi and web path alias.
+
+Note that warden_ra itself is NOT thread safe, so included configuration
+expects Apache with mpm-prefork worker, or you will have to configure
+mod_wsgi as separate process with threads=1.
+
+Also, for warden_server.wsgi, you can use warden_server.wsgi.dist as
+a template. You will possibly need to change at least configuration
+file path.
+
+ * Configure Warden RA (see next chapter)
+
+ * Reload Apache
+
+
+Configuration
+-------------
+
+   Configuration is JSON object in file (warden_server.cfg by default),
+however, lines starting with "#" or "//" are allowed and will be ignored as
+comments. File must contain valid JSON object, containing configuration. See
+also warden_server.cfg.dist as example.
+
+   Top level JSON object contains subsections, which configure particular
+aspect of the server. Each subsection can contain "type" key, which chooses
+particular implementation object of the aspect, for example type of logger
+(file, syslog), such as:
+
+   {
+      "Log": {
+         "type": "SysLogger",
+         ...
+      },
+      "DB": { ... }
+   }
+
+Sections and their "type" objects can be:
+
+    Log: FileLogger, SysLogger
+    Auth: OptionalAuthenticator
+    Registry: EjbcaRegistry
+    Handler: CertHandler
+
+"type" keyword is not mandatory, if not specified, first implementation
+object from particular section list is used ("FileLogger" for example).
+
+Object function and configuration keys are as follows:
+
+   FileLogger: logging into file on the filesystem
+      filename: name of the file, defaults to "warden_ra.log" at
+                installation directory
+      level: least log level (CRITICAL, ERROR, WARNING, INFO, DEBUG)
+
+   SysLogger: logging into unix syslog
+      socket: path to syslog socket, defaults to "/dev/log"
+      facility: syslog facility, defaults to "daemon"
+      level: least log level (CRITICAL, ERROR, WARNING, INFO, DEBUG)
+
+    OptionalAuthenticator: authenticate based on X509 certificate, or
+        signal the password auth for the registry
+
+    CertHandler: the main certificate requestor implementation
+
+    EjbcaRegistry: EJBCA connector configuration
+        url: EJBCA API URL, for example "https://ejbca.example.org/ejbca/ejbcaws/ejbcaws?wsdl"
+        cert: certificate for authentication to EJBCA, defaults to "warden_ra.cert.pem"
+        key: key for authentication to EJBCA, defaults to "warden_ra.key.pem"
+        ca_name: name of the CA, dedicated for Warden, defaults to "Example CA"
+        certificate_profile_name: name of the EJBCA certificate profile, defaults to "Example"
+        end_entity_profile_name: name of the EJBCA entity profile, defaults to "Example EE"
+        subject_dn_template: template for the DN generation, defaults to "DC=cz,DC=example-ca,DC=warden,CN=%s"
+        username_suffix: suffix, which will be added to EJBCA entities, defaults to "@warden"
+
+
+Command line
+------------
+
+Whe run from the command line, RA allows for client and request management.
+
+
+    warden_ra.py [--help] [-c CONFIG] [-v]
+                        {list,register,applicant,request,gencert} ...
+
+    Warden server certificate registry
+    
+    arguments:
+      --help                show this help message and exit
+      -c CONFIG, --config CONFIG
+                            path to configuration file
+      -v, --verbose         be more chatty
+    
+    commands:
+      {list,register,applicant,request,gencert}
+        list                list clients
+        register            register client
+        applicant           allow for certificate application
+        request             generate CSR
+        gencert             get new certificate
+
+
+    warden_ra.py list [--help] [--name NAME]
+    
+    List registered clients.
+    
+    arguments:
+      --help       show this help message and exit
+      --name NAME  client name
+
+
+    warden_ra.py register [--help] --name NAME --admins
+                                 [ADMINS [ADMINS ...]]
+    
+    Add client registration entry.
+    
+    arguments:
+      --help                show this help message and exit
+      --name NAME           client name
+      --admins [ADMINS [ADMINS ...]]
+                            administrator list
+
+
+    warden_ra.py applicant [--help] --name NAME [--password PASSWORD]
+    
+    Set client into certificate application mode and set its password
+    
+    optional arguments:
+      --help               show this help message and exit
+      --name NAME          client name
+      --password PASSWORD  password for application (will be autogenerated if not
+                           set)
+
+    
+.. _Warden: https://warden.cesnet.cz/
+.. _EJBCA: https://www.ejbca.org/
+
+------------------------------------------------------------------------------
+
+Copyright (C) 2017 Cesnet z.s.p.o
diff --git a/warden3/contrib/warden_ra/apache22.conf b/warden3/contrib/warden_ra/apache22.conf
index cea3317dacfb34b47d6e97cef353d7a1e8753581..93ca7f805491066748f5393d210edd3687022eeb 100644
--- a/warden3/contrib/warden_ra/apache22.conf
+++ b/warden3/contrib/warden_ra/apache22.conf
@@ -1,6 +1,6 @@
 SSLEngine on
 
-SSLVerifyClient none
+SSLVerifyClient optional
 SSLOptions +StdEnvVars +ExportCertData
 
 SSLCertificateFile      /opt/warden_server_3/cert.pem
diff --git a/warden3/contrib/warden_ra/warden_apply.sh b/warden3/contrib/warden_ra/warden_apply.sh
old mode 100755
new mode 100644
index 1992a981761f5672b98d7331032cc6d9cf1e5d68..bb9bae46132e2e2320e27c37a86d8bbbcb2c1777
--- a/warden3/contrib/warden_ra/warden_apply.sh
+++ b/warden3/contrib/warden_ra/warden_apply.sh
@@ -8,12 +8,14 @@ result=${TMPDIR:-${TMP:-/tmp}}/cert.$$.$RANDOM
 config=${TMPDIR:-${TMP:-/tmp}}/conf.$$.$RANDOM
 client="$1"
 password="$2"
+incert="$2"
+inkey="$3"
 
 trap 'rm -f "$config $result"' INT TERM HUP EXIT
 
 function flee { echo -e "$1"; exit $2; }
 
-[ -z "$client" -o -z "$password" ] && flee "Usage: ${0%.*} client.name password" 255
+[ -z "$client" -o -z "$password" ] && flee "Usage: ${0%.*} client.name password\n       ${0%.*} client.name cert_file key_file" 255
 
 for n in openssl curl; do
     command -v "$n" 2>&1 >/dev/null || flee "Haven't found $n binary." 251
@@ -29,7 +31,11 @@ echo -e "default_bits=2048\ndistinguished_name=rdn\nprompt=no\n[rdn]\ncommonName
 
 openssl req -new -nodes -batch -keyout "$key" -out "$csr" -config "$config" || flee "Error generating key/certificate request." 252
 
-curl --progress-bar --request POST --data-binary '@-' "$url?name=$client&password=$password" < "$csr" > "$result"
+if [ -z "$inkey" ]; then
+	curl --progress-bar --request POST --data-binary '@-' "$url?name=$client&password=$password" < "$csr" > "$result"
+else
+	curl --progress-bar --request POST --data-binary '@-' --cert "$incert" --key "$inkey" "$url?name=$client" < "$csr" > "$result"
+fi
 
 case $(<$result) in '-----BEGIN CERTIFICATE-----'*)
     mv "$result" "$cert"
diff --git a/warden3/contrib/warden_ra/warden_ra.py b/warden3/contrib/warden_ra/warden_ra.py
index 2ae698ce2a9a2eacbf832f4e5a354b27284728f7..9437bf17f6bc376fd9910426976a3498b1d5003a 100755
--- a/warden3/contrib/warden_ra/warden_ra.py
+++ b/warden3/contrib/warden_ra/warden_ra.py
@@ -167,7 +167,7 @@ def format_cert(cert):
 
 # Server side
 
-class NullAuthenticator(ObjectBase):
+class OptionalAuthenticator(ObjectBase):
 
     def __init__(self, req, log):
         ObjectBase.__init__(self, req, log)
@@ -178,7 +178,30 @@ class NullAuthenticator(ObjectBase):
 
 
     def authenticate(self, env, args):
-        return True
+        cert_name = env.get("SSL_CLIENT_S_DN_CN")
+
+        if cert_name:
+            if cert_name != args.setdefault("name", [cert_name])[0]:
+                exception = self.req.error(message="authenticate: client name does not correspond with certificate", error=403, cn = cert_name, args = args)
+                exception.log(self.log)
+                return None
+
+            verify = env.get("SSL_CLIENT_VERIFY")
+            if verify != "SUCCESS":
+                exception = self.req.error(message="authenticate: certificate present but verification failed", error=403, cn = cert_name, args = args, verify=verify)
+                exception.log(self.log)
+                return None
+
+            return "cert"   # Ok, client authorized by valid certificate
+
+        else:
+            try:
+                args["password"][0]
+                return "pwd"    # Ok, pass on, but getCert will have to rely on certificate registry password
+            except KeyError, IndexError:
+                exception = self.req.error(message="authenticate: no certificate nor password present", error=403, cn = cert_name, args = args)
+                exception.log(self.log)
+                return None
 
 
     def authorize(self, env, client, path, method):
@@ -193,12 +216,21 @@ class CertHandler(ObjectBase):
 
     @expose(read=1, debug=1)
     def getCert(self, csr_data=None, name=None, password=None):
-        if not (name and password and csr_data):
-            raise self.req.error(message="Wrong or missing arguments", error=400, client=name[0], password=password[0])
+        if not (name and csr_data):
+            raise self.req.error(message="Wrong or missing arguments", error=400, name=name, password=password)
         client = self.registry.get_client(name[0])
         if not client:
-            raise self.req.error(message="Unknown client", error=403, client=name[0], password=password[0])
-        self.log.info("Client: %s" % client.name)
+            raise self.req.error(message="Unknown client", error=403, name=name, password=password)
+        self.log.info("Client %s" % client.name)
+        if self.req.client == "cert":
+            # Correctly authenticated by cert, most probably not preactivated with password,
+            # so generate oneshot password and allow now
+            password = "".join((random.choice(string.ascii_letters + string.digits) for dummy in range(16)))
+            self.log.debug("Authorized by X509, enabling cert generation with password %s" % password)
+            client.allow_new_cert(pwd=password)
+            client.save()
+        if not password:
+            raise self.req.error(message="Missing password and certificate validation failed", error=403, name=name, password=password)
         try:
             newcert = client.new_cert(csr_data, password)
         except Exception as e:
@@ -215,7 +247,7 @@ section_order = ("log", "auth", "registry", "handler", "server")
 # "type" keyword in section may be used to choose other
 section_def = {
     "log": [FileLogger, SysLogger],
-    "auth": [NullAuthenticator],
+    "auth": [OptionalAuthenticator],
     "registry": [EjbcaRegistry],
     "handler": [CertHandler],
     "server": [Server]
@@ -226,7 +258,7 @@ param_def = {
     FileLogger: warden_server.param_def[FileLogger],
     SysLogger: warden_server.param_def[SysLogger],
     Server: warden_server.param_def[Server],
-    NullAuthenticator: {
+    OptionalAuthenticator: {
         "req": {"type": "obj", "default": "req"},
         "log": {"type": "obj", "default": "log"}
     },