[469467] Fixes and documentation to use_subject_as_username patch.

This is for certificate based client authentication.

Thanks to Fabian Ruff.

Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=469467
This commit is contained in:
Roger A. Light 2015-06-12 22:52:15 +01:00
parent f0511d0ff7
commit 7657aac584
5 changed files with 61 additions and 17 deletions

View File

@ -14,6 +14,9 @@ Broker:
up. Once the backlog has cleared the client will respond. If it is not
able to catch up, sending additional duplicates would not help either.
- Produce an error if two bridges share the same local_clientid.
- Add use_subject_as_username option for certificate based client
authentication to use the entire certificate subject as a username, rather
than just the CN. Closes #469467.
Client library:
- Outgoing messages with QoS>1 are no longer retried after a timeout period.

View File

@ -21,6 +21,7 @@ Dirk O. Kaar
Dominik Obermaier
Dominik Zajac
Ed Morris
Fabian Ruff
Frank Hansen
Gary Koh
Joan Zapata

View File

@ -52,7 +52,7 @@
usernames and passwords. Be sure to use network encryption if you
are using this option otherwise the username and password will be
vulnerable to interception.</para>
<para>When using certificate based encryption there are two options
<para>When using certificate based encryption there are three options
that affect authentication. The first is require_certificate, which
may be set to true or false. If false, the SSL/TLS component of the
client will verify the server but there is no requirement for the
@ -60,14 +60,17 @@
limited to the MQTT built in username/password. If
require_certificate is true, the client must provide a valid
certificate in order to connect successfully. In this case, the
second option, use_identity_as_username, becomes relevant. If set
to true, the Common Name (CN) from the client certificate is used
instead of the MQTT username for access control purposes. The
password is not replaced because it is assumed that only
authenticated clients have valid certificates. If
second and third options, use_identity_as_username and
use_subject_as_username, become relevant. If set to true,
use_identity_as_user causes the Common Name (CN) from the client
certificate to be used instead of the MQTT username for access
control purposes. The password is not replaced because it is
assumed that only authenticated clients have valid certificates. If
use_identity_as_username is false, the client must authenticate as
normal (if required by password_file) through the MQTT
options.</para>
normal (if required by password_file) through the MQTT options. The
same principle applies for the use_subject_as_username option, but
the entire certificate subject is used as the username instead of
just the CN.</para>
<para>When using pre-shared-key based encryption through the psk_hint
and psk_file options, the client must provide a valid identity and
key in order to connect to the broker before any MQTT communication
@ -823,6 +826,28 @@
is <replaceable>true</replaceable>, the
<option>password_file</option> option will not be
used for this listener.</para>
<para>This takes priority over
<option>use_subject_as_username</option> if both
are set to <replaceable>true</replaceable>.</para>
<para>See also
<option>use_subject_as_username</option></para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>use_subject_as_username</option> [ true | false ]</term>
<listitem>
<para>If <option>require_certificate</option> is
<replaceable>true</replaceable>, you may set
<option>use_subject_as_username</option> to
<replaceable>true</replaceable> to use the complete subject value
from the client certificate as a username. If this
is <replaceable>true</replaceable>, the
<option>password_file</option> option will not be
used for this listener.</para>
<para>The subject will be generated in a form similar
to <option>CN=test client,OU=Production,O=Server,L=Nottingham,ST=Nottinghamshire,C=GB</option>.</para>
<para>See also
<option>use_identity_as_username</option></para>
</listitem>
</varlistentry>
</variablelist>

View File

@ -208,8 +208,16 @@
# If require_certificate is true, you may set use_identity_as_username to true
# to use the CN value from the client certificate as a username. If this is
# true, the password_file option will not be used for this listener.
# This takes priority over use_subject_as_username.
# See also use_subject_as_username.
#use_identity_as_username false
# If require_certificate is true, you may set use_subject_as_username to true
# to use the complete subject value from the client certificate as a username.
# If this is true, the password_file option will not be used for this listener.
# See also use_identity_as_username
#use_subject_as_username false
# If you have require_certificate set to true, you can create a certificate
# revocation list file to revoke access to particular client certificates. If
# you have done this, use crlfile to point to the PEM encoded revocation file.

View File

@ -344,16 +344,23 @@ int handle__connect(struct mosquitto_db *db, struct mosquitto *context)
goto handle_connect_error;
}
name_entry = X509_NAME_get_entry(name, i);
context->username = _mosquitto_strdup((char *)ASN1_STRING_data(name_entry->value));
if(name_entry){
context->username = mosquitto__strdup((char *)ASN1_STRING_data(name_entry->value));
}
} else { // use_subject_as_username
BIO *subjectBio = BIO_new(BIO_s_mem());
X509_NAME_print_ex(subjectBio, X509_get_subject_name(client_cert) , 0, XN_FLAG_RFC2253);
char *dataStart = NULL;
long nameLength = BIO_get_mem_data(subjectBio, &dataStart);
char *subject = mosquitto__malloc(sizeof(char)*nameLength);
memset(subject, 0x00, sizeof(char)*(nameLength + 1));
memcpy(subject, dataStart, nameLength);
BIO_free(subjectBio);
BIO *subject_bio = BIO_new(BIO_s_mem());
X509_NAME_print_ex(subject_bio, X509_get_subject_name(client_cert), 0, XN_FLAG_RFC2253);
char *data_start = NULL;
long name_length = BIO_get_mem_data(subject_bio, &data_start);
char *subject = mosquitto__malloc(sizeof(char)*name_length+1);
if(!subject){
BIO_free(subject_bio);
rc = MOSQ_ERR_NOMEM;
goto handle_connect_error;
}
memcpy(subject, data_start, name_length);
subject[name_length] = '\0';
BIO_free(subject_bio);
context->username = subject;
}
if(!context->username){