spnego: Support ASN.1 BIT STRING and use it in SPNEGO.
authorKouhei Sutou <kou@clear-code.com>
Thu, 13 Aug 2009 06:12:01 +0000 (15:12 +0900)
committerGünther Deschner <gd@samba.org>
Thu, 17 Sep 2009 18:10:54 +0000 (20:10 +0200)
Signed-off-by: Günther Deschner <gd@samba.org>
lib/util/asn1.c
lib/util/asn1.h
libcli/auth/spnego.h
libcli/auth/spnego_parse.c
source3/utils/ntlm_auth.c
source4/auth/gensec/spnego.c

index 317ee1314c6095a7213d8e55c9633aa2798823c3..70c2c57450cc1de869fab961de8ea55911e8c9e4 100644 (file)
@@ -205,6 +205,15 @@ bool asn1_write_Integer(struct asn1_data *data, int i)
        return asn1_pop_tag(data);
 }
 
+/* write a BIT STRING */
+bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding)
+{
+       if (!asn1_push_tag(data, ASN1_BIT_STRING)) return false;
+       if (!asn1_write_uint8(data, padding)) return false;
+       if (!asn1_write(data, p, length)) return false;
+       return asn1_pop_tag(data);
+}
+
 bool ber_write_OID_String(DATA_BLOB *blob, const char *OID)
 {
        uint_t v, v2;
@@ -727,6 +736,39 @@ bool asn1_read_Integer(struct asn1_data *data, int *i)
        return asn1_end_tag(data);      
 }
 
+/* read a BIT STRING */
+bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding)
+{
+       int len;
+       ZERO_STRUCTP(blob);
+       if (!asn1_start_tag(data, ASN1_BIT_STRING)) return false;
+       len = asn1_tag_remaining(data);
+       if (len < 0) {
+               data->has_error = true;
+               return false;
+       }
+       if (!asn1_read_uint8(data, padding)) return false;
+
+       *blob = data_blob_talloc(mem_ctx, NULL, len);
+       if (!blob->data) {
+               data->has_error = true;
+               return false;
+       }
+       if (asn1_read(data, blob->data, len - 1)) {
+               blob->length--;
+               blob->data[len] = 0;
+               asn1_end_tag(data);
+       }
+
+       if (data->has_error) {
+               data_blob_free(blob);
+               *blob = data_blob_null;
+               *padding = 0;
+               return false;
+       }
+       return true;
+}
+
 /* read an integer */
 bool asn1_read_enumerated(struct asn1_data *data, int *v)
 {
index 4c6624056e0c6973f4945ec4055d54b63f4a3253..9abae50d64ef6c1e1c905076d647eaccaa4287b7 100644 (file)
@@ -60,6 +60,7 @@ bool asn1_push_tag(struct asn1_data *data, uint8_t tag);
 bool asn1_pop_tag(struct asn1_data *data);
 bool asn1_write_implicit_Integer(struct asn1_data *data, int i);
 bool asn1_write_Integer(struct asn1_data *data, int i);
+bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding);
 bool ber_write_OID_String(DATA_BLOB *blob, const char *OID);
 bool asn1_write_OID(struct asn1_data *data, const char *OID);
 bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length);
@@ -90,6 +91,7 @@ bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLO
 bool asn1_read_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob);
 bool asn1_read_implicit_Integer(struct asn1_data *data, int *i);
 bool asn1_read_Integer(struct asn1_data *data, int *i);
+bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding);
 bool asn1_read_enumerated(struct asn1_data *data, int *v);
 bool asn1_check_enumerated(struct asn1_data *data, int v);
 bool asn1_write_enumerated(struct asn1_data *data, uint8_t v);
index 08350a44ff3db1111a5275533b892f1eb2cea2d1..4b60f22d32d09291c00f54559659caf81e901202 100644 (file)
@@ -32,7 +32,6 @@
 #define SPNEGO_ANON_FLAG     0x10
 #define SPNEGO_CONF_FLAG     0x20
 #define SPNEGO_INTEG_FLAG    0x40
-#define SPNEGO_REQ_FLAG      0x80
 
 enum spnego_negResult {
        SPNEGO_ACCEPT_COMPLETED = 0,
@@ -43,7 +42,8 @@ enum spnego_negResult {
 
 struct spnego_negTokenInit {
        const char **mechTypes;
-       int reqFlags;
+       DATA_BLOB reqFlags;
+       uint8_t reqFlagsPadding;
        DATA_BLOB mechToken;
        DATA_BLOB mechListMIC;
        char *targetPrincipal;
index 27e57740dc2e921551d001f6f7fa2fc11eaa379f..3f7047b0e0bdccd51f2eafd4d60bc8f15f694b34 100644 (file)
@@ -62,8 +62,8 @@ static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
                /* Read reqFlags */
                case ASN1_CONTEXT(1):
                        asn1_start_tag(asn1, ASN1_CONTEXT(1));
-                       asn1_read_Integer(asn1, &token->reqFlags);
-                       token->reqFlags |= SPNEGO_REQ_FLAG;
+                       asn1_read_BitString(asn1, mem_ctx, &token->reqFlags,
+                                           &token->reqFlagsPadding);
                        asn1_end_tag(asn1);
                        break;
                 /* Read mechToken */
@@ -130,11 +130,11 @@ static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenIni
        }
 
        /* write reqFlags */
-       if (token->reqFlags & SPNEGO_REQ_FLAG) {
-               int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
-
+       if (token->reqFlags.length > 0) {
                asn1_push_tag(asn1, ASN1_CONTEXT(1));
-               asn1_write_Integer(asn1, flags);
+               asn1_write_BitString(asn1, token->reqFlags.data,
+                                    token->reqFlags.length,
+                                    token->reqFlagsPadding);
                asn1_pop_tag(asn1);
        }
 
@@ -353,6 +353,7 @@ bool spnego_free_data(struct spnego_data *spnego)
                if (spnego->negTokenInit.mechTypes) {
                        talloc_free(spnego->negTokenInit.mechTypes);
                }
+               data_blob_free(&spnego->negTokenInit.reqFlags);
                data_blob_free(&spnego->negTokenInit.mechToken);
                data_blob_free(&spnego->negTokenInit.mechListMIC);
                talloc_free(spnego->negTokenInit.targetPrincipal);
index a607cb0658784eb010568520ced555090bf8123c..3bdc45a6ef7f092c85173414715d5fe1d952f3ab 100644 (file)
@@ -1454,7 +1454,8 @@ static bool manage_client_ntlmssp_init(struct spnego_data spnego)
 
        spnego.type = SPNEGO_NEG_TOKEN_INIT;
        spnego.negTokenInit.mechTypes = my_mechs;
-       spnego.negTokenInit.reqFlags = 0;
+       spnego.negTokenInit.reqFlags = data_blob_null;
+       spnego.negTokenInit.reqFlagsPadding = 0;
        spnego.negTokenInit.mechListMIC = null_blob;
 
        status = ntlmssp_update(client_ntlmssp_state, null_blob,
@@ -1609,7 +1610,8 @@ static bool manage_client_krb5_init(struct spnego_data spnego)
 
        reply.type = SPNEGO_NEG_TOKEN_INIT;
        reply.negTokenInit.mechTypes = my_mechs;
-       reply.negTokenInit.reqFlags = 0;
+       reply.negTokenInit.reqFlags = data_blob_null;
+       reply.negTokenInit.reqFlagsPadding = 0;
        reply.negTokenInit.mechToken = tkt;
        reply.negTokenInit.mechListMIC = data_blob_null;
 
index 8f06eab8bbe97fbebff9a7f88de2114a9b15f9f9..977d52ec10798b1686a86fc561b46551ab82290e 100644 (file)
@@ -628,7 +628,8 @@ static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec
 
                /* List the remaining mechs as options */
                spnego_out.negTokenInit.mechTypes = send_mech_types;
-               spnego_out.negTokenInit.reqFlags = 0;
+               spnego_out.negTokenInit.reqFlags = null_data_blob;
+               spnego_out.negTokenInit.reqFlagsPadding = 0;
                
                if (spnego_state->state_position == SPNEGO_SERVER_START) {
                        /* server credentials */
@@ -844,7 +845,8 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
                /* compose reply */
                spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
                spnego_out.negTokenInit.mechTypes = my_mechs;
-               spnego_out.negTokenInit.reqFlags = 0;
+               spnego_out.negTokenInit.reqFlags = null_data_blob;
+               spnego_out.negTokenInit.reqFlagsPadding = 0;
                spnego_out.negTokenInit.mechListMIC = null_data_blob;
                spnego_out.negTokenInit.mechToken = unwrapped_out;