/* Decode a single PASSDSS packet */ static int passdss_decode_packet(void *context, const char *input, unsigned inputlen, char **output, unsigned *outputlen) { context_t *text = (context_t *) context; uint32_t tmpnum; unsigned char hmac[EVP_MAX_MD_SIZE]; unsigned hmaclen; int ret; if (text->secmask & PRIVACY_LAYER_FLAG) { unsigned declen, padlen; /* allocate a buffer for the output */ ret = _plug_buf_alloc(text->utils, &(text->decode_pkt_buf), &(text->decode_pkt_buf_len), inputlen); if (ret != SASL_OK) return ret; /* decrypt the data into the output buffer */ ret = EVP_DecryptUpdate(&text->cipher_dec_ctx, text->decode_pkt_buf, &declen, (char *) input, inputlen); if (ret) EVP_DecryptFinal_ex(&text->cipher_dec_ctx, /* should be no output */ text->decode_pkt_buf + declen, &declen); if (!ret) { SETERROR(text->utils, "Error decrypting input"); return SASL_BADPROT; } input = text->decode_pkt_buf; /* trim padding */ padlen = text->decode_pkt_buf[inputlen - 1] + 1; inputlen -= padlen; } /* trim HMAC */ inputlen -= SHA_DIGEST_LENGTH; /* prepend packet number to integrity key */ tmpnum = htonl(text->pktnum_in++); memcpy(text->recv_integrity_key, &tmpnum, 4); /* calculate the HMAC */ HMAC(EVP_sha1(), text->recv_integrity_key, 4+SHA_DIGEST_LENGTH, input, inputlen, hmac, &hmaclen); /* verify HMAC */ if (memcmp(hmac, input+inputlen, hmaclen)) { SETERROR(text->utils, "HMAC is incorrect\n"); return SASL_BADMAC; } *output = (char *) input; *outputlen = inputlen; return SASL_OK; }
static int kerberosv4_decode_packet(void *context, const char *input, unsigned inputlen, char **output, unsigned *outputlen) { context_t *text = (context_t *) context; int result; MSG_DAT data; memset(&data,0,sizeof(MSG_DAT)); KRB_LOCK_MUTEX(text->utils); if (text->sec_type == KRB_SEC_ENCRYPTION) { result=krb_rd_priv(input, inputlen, text->init_keysched, &text->session, &text->ip_remote, &text->ip_local, &data); } else if (text->sec_type == KRB_SEC_INTEGRITY) { result = krb_rd_safe(input, inputlen, &text->session, &text->ip_remote, &text->ip_local, &data); } else { KRB_UNLOCK_MUTEX(text->utils); text->utils->seterror(text->utils->conn, 0, "KERBEROS_4 decode called with KRB_SEC_NONE"); return SASL_FAIL; } KRB_UNLOCK_MUTEX(text->utils); /* see if the krb library gave us a failure */ if (result != 0) { text->utils->seterror(text->utils->conn, 0, get_krb_err_txt(result)); return SASL_FAIL; } /* check to make sure the timestamps are ok */ if ((data.time_sec < text->time_sec) || /* if an earlier time */ (((data.time_sec == text->time_sec) && /* or the exact same time */ (data.time_5ms < text->time_5ms)))) { text->utils->seterror(text->utils->conn, 0, "timestamps not ok"); return SASL_FAIL; } text->time_sec = data.time_sec; text->time_5ms = data.time_5ms; result = _plug_buf_alloc(text->utils, &text->decode_once_buf, &text->decode_once_buf_len, data.app_length + 1); if(result != SASL_OK) return result; *output = text->decode_once_buf; *outputlen = data.app_length; memcpy(*output, data.app_data, data.app_length); (*output)[*outputlen] = '\0'; return SASL_OK; }
static int kerberosv4_encode(void *context, const struct iovec *invec, unsigned numiov, const char **output, unsigned *outputlen) { int len, ret; context_t *text = (context_t *)context; struct buffer_info *inblob, bufinfo; if(numiov > 1) { ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf); if(ret != SASL_OK) return ret; inblob = text->enc_in_buf; } else { bufinfo.data = invec[0].iov_base; bufinfo.curlen = invec[0].iov_len; inblob = &bufinfo; } ret = _plug_buf_alloc(text->utils, &(text->encode_buf), &text->encode_buf_len, inblob->curlen+40); if(ret != SASL_OK) return ret; KRB_LOCK_MUTEX(text->utils); if (text->sec_type == KRB_SEC_ENCRYPTION) { /* Type incompatibility on 4th arg probably means you're building against krb4 in MIT krb5, but got the OpenSSL headers in your way. You need to not use openssl/des.h with MIT kerberos. */ len=krb_mk_priv(inblob->data, (text->encode_buf+4), inblob->curlen, text->init_keysched, &text->session, &text->ip_local, &text->ip_remote); } else if (text->sec_type == KRB_SEC_INTEGRITY) { len=krb_mk_safe(inblob->data, (text->encode_buf+4), inblob->curlen, &text->session, &text->ip_local, &text->ip_remote); } else { len = -1; } KRB_UNLOCK_MUTEX(text->utils); /* returns -1 on error */ if (len==-1) return SASL_FAIL; /* now copy in the len of the buffer in network byte order */ *outputlen=len+4; len=htonl(len); memcpy(text->encode_buf, &len, 4); /* Setup the const pointer */ *output = text->encode_buf; return SASL_OK; }
static int passdss_encode(void *context, const struct iovec *invec, unsigned numiov, const char **output, unsigned *outputlen) { context_t *text = (context_t *) context; unsigned long inputlen; unsigned char hmac[EVP_MAX_MD_SIZE]; unsigned i, hmaclen; uint32_t tmpnum; int ret; if (!context || !invec || !numiov || !output || !outputlen) { PARAMERROR( text->utils ); return SASL_BADPARAM; } /* calculate total size of input */ for (i = 0, inputlen = 0; i < numiov; i++) inputlen += invec[i].iov_len; /* allocate a buffer for the output */ ret = _plug_buf_alloc(text->utils, &text->encode_buf, &text->encode_buf_len, 4 + /* length */ inputlen + /* content */ EVP_MAX_MD_SIZE + /* HMAC */ EVP_MAX_BLOCK_LENGTH - 1); /* padding */ if (ret != SASL_OK) return ret; *outputlen = 4; /* skip length */ /* prepend packet number to integrity key */ tmpnum = htonl(text->pktnum_out++); memcpy(text->send_integrity_key, &tmpnum, 4); /* key the HMAC */ HMAC_Init_ex(&text->hmac_send_ctx, text->send_integrity_key, 4+SHA_DIGEST_LENGTH, EVP_sha1(), NULL); /* operate on each iovec */ for (i = 0; i < numiov; i++) { /* hash the content */ HMAC_Update(&text->hmac_send_ctx, invec[i].iov_base, invec[i].iov_len); if (text->secmask & PRIVACY_LAYER_FLAG) { unsigned enclen; /* encrypt the data into the output buffer */ EVP_EncryptUpdate(&text->cipher_enc_ctx, text->encode_buf + *outputlen, &enclen, invec[i].iov_base, invec[i].iov_len); *outputlen += enclen; } else { /* copy the raw input to the output */ memcpy(text->encode_buf + *outputlen, invec[i].iov_base, invec[i].iov_len); *outputlen += invec[i].iov_len; } } /* calculate the HMAC */ HMAC_Final(&text->hmac_send_ctx, hmac, &hmaclen); if (text->secmask & PRIVACY_LAYER_FLAG) { unsigned enclen; unsigned char padlen; /* encrypt the HMAC into the output buffer */ EVP_EncryptUpdate(&text->cipher_enc_ctx, text->encode_buf + *outputlen, &enclen, hmac, hmaclen); *outputlen += enclen; /* pad output buffer to multiple of blk_siz with padlen-1 as last octet */ padlen = text->blk_siz - ((inputlen + hmaclen) % text->blk_siz) - 1; EVP_EncryptUpdate(&text->cipher_enc_ctx, text->encode_buf + *outputlen, &enclen, text->padding, padlen); *outputlen += enclen; EVP_EncryptUpdate(&text->cipher_enc_ctx, text->encode_buf + *outputlen, &enclen, &padlen, 1); *outputlen += enclen; /* encrypt the last block of data into the output buffer */ EVP_EncryptFinal_ex(&text->cipher_enc_ctx, text->encode_buf + *outputlen, &enclen); *outputlen += enclen; } else { /* copy the HMAC to the output */ memcpy(text->encode_buf + *outputlen, hmac, hmaclen); *outputlen += hmaclen; } /* prepend the length of the output */ tmpnum = *outputlen - 4; tmpnum = htonl(tmpnum); memcpy(text->encode_buf, &tmpnum, 4); *output = text->encode_buf; return SASL_OK; }
static int gssapi_decode_packet(void *context, const char *input, unsigned inputlen, char **output, unsigned *outputlen) { context_t *text = (context_t *) context; OM_uint32 maj_stat, min_stat; gss_buffer_t input_token, output_token; gss_buffer_desc real_input_token, real_output_token; int result; if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) { SETERROR(text->utils, "GSSAPI Failure"); return SASL_NOTDONE; } input_token = &real_input_token; real_input_token.value = (char *) input; real_input_token.length = inputlen; output_token = &real_output_token; output_token->value = NULL; output_token->length = 0; GSS_LOCK_MUTEX(text->utils); maj_stat = gss_unwrap (&min_stat, text->gss_ctx, input_token, output_token, NULL, NULL); GSS_UNLOCK_MUTEX(text->utils); if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils,maj_stat,min_stat); if (output_token->value) { GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils); } return SASL_FAIL; } if (outputlen) *outputlen = output_token->length; if (output_token->value) { if (output) { result = _plug_buf_alloc(text->utils, &text->decode_once_buf, &text->decode_once_buf_len, *outputlen); if(result != SASL_OK) { GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils); return result; } *output = text->decode_once_buf; memcpy(*output, output_token->value, *outputlen); } GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils); } return SASL_OK; }
static int sasl_gss_encode(void *context, const struct iovec *invec, unsigned numiov, const char **output, unsigned *outputlen, int privacy) { context_t *text = (context_t *)context; OM_uint32 maj_stat, min_stat; gss_buffer_t input_token, output_token; gss_buffer_desc real_input_token, real_output_token; int ret; struct buffer_info *inblob, bufinfo; if(!output) return SASL_BADPARAM; if(numiov > 1) { ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf); if(ret != SASL_OK) return ret; inblob = text->enc_in_buf; } else { bufinfo.data = invec[0].iov_base; bufinfo.curlen = invec[0].iov_len; inblob = &bufinfo; } if (text->state != SASL_GSSAPI_STATE_AUTHENTICATED) return SASL_NOTDONE; input_token = &real_input_token; real_input_token.value = inblob->data; real_input_token.length = inblob->curlen; output_token = &real_output_token; output_token->value = NULL; output_token->length = 0; GSS_LOCK_MUTEX(text->utils); maj_stat = gss_wrap (&min_stat, text->gss_ctx, privacy, GSS_C_QOP_DEFAULT, input_token, NULL, output_token); GSS_UNLOCK_MUTEX(text->utils); if (GSS_ERROR(maj_stat)) { sasl_gss_seterror(text->utils, maj_stat, min_stat); if (output_token->value) { GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils); } return SASL_FAIL; } if (output_token->value && output) { int len; ret = _plug_buf_alloc(text->utils, &(text->encode_buf), &(text->encode_buf_len), output_token->length + 4); if (ret != SASL_OK) { GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils); return ret; } len = htonl(output_token->length); memcpy(text->encode_buf, &len, 4); memcpy(text->encode_buf + 4, output_token->value, output_token->length); } if (outputlen) { *outputlen = output_token->length + 4; } *output = text->encode_buf; if (output_token->value) { GSS_LOCK_MUTEX(text->utils); gss_release_buffer(&min_stat, output_token); GSS_UNLOCK_MUTEX(text->utils); } return SASL_OK; }
static int sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min, int logonly) { OM_uint32 maj_stat, min_stat; gss_buffer_desc msg; OM_uint32 msg_ctx; int ret; char *out = NULL; size_t len, curlen = 0; const char prefix[] = "GSSAPI Error: "; len = sizeof(prefix); ret = _plug_buf_alloc(utils, &out, &curlen, 256); if(ret != SASL_OK) return SASL_OK; strcpy(out, prefix); msg_ctx = 0; while (1) { GSS_LOCK_MUTEX(utils); maj_stat = gss_display_status(&min_stat, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); GSS_UNLOCK_MUTEX(utils); if(GSS_ERROR(maj_stat)) { if (logonly) { utils->log(utils->conn, SASL_LOG_FAIL, "GSSAPI Failure: (could not get major error message)"); } else { utils->seterror(utils->conn, 0, "GSSAPI Failure " "(could not get major error message)"); } utils->free(out); return SASL_OK; } len += len + msg.length; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_OK; } strcat(out, msg.value); GSS_LOCK_MUTEX(utils); gss_release_buffer(&min_stat, &msg); GSS_UNLOCK_MUTEX(utils); if (!msg_ctx) break; } /* Now get the minor status */ len += 2; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_NOMEM; } strcat(out, " ("); msg_ctx = 0; while (1) { GSS_LOCK_MUTEX(utils); maj_stat = gss_display_status(&min_stat, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); GSS_UNLOCK_MUTEX(utils); if(GSS_ERROR(maj_stat)) { if (logonly) { utils->log(utils->conn, SASL_LOG_FAIL, "GSSAPI Failure: (could not get minor error message)"); } else { utils->seterror(utils->conn, 0, "GSSAPI Failure " "(could not get minor error message)"); } utils->free(out); return SASL_OK; } len += len + msg.length; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_NOMEM; } strcat(out, msg.value); GSS_LOCK_MUTEX(utils); gss_release_buffer(&min_stat, &msg); GSS_UNLOCK_MUTEX(utils); if (!msg_ctx) break; } len += 1; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_NOMEM; } strcat(out, ")"); if (logonly) { utils->log(utils->conn, SASL_LOG_FAIL, out); } else { utils->seterror(utils->conn, 0, out); } utils->free(out); return SASL_OK; }