int localsm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) { u_char **wholeMsg = parms->wholeMsg; size_t *offset = parms->wholeMsgOffset; int rc; size_t *wholeMsgLen = parms->wholeMsgLen; DEBUGMSGTL(("localsm", "Starting LOCALSM processing\n")); /* * We define here what the security message section will look like: * 04 00 -- null string * XXX: need to actually negotiate a context engine ID? * XXX: leave room for future expansion just in case? */ DEBUGDUMPHEADER("send", "localsm security parameters"); rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), 0); DEBUGINDENTLESS(); if (rc == 0) { DEBUGMSGTL(("localsm", "building msgSecurityParameters failed.\n")); return SNMPERR_TOO_LONG; } /* * Copy in the msgGlobalData and msgVersion. */ while ((*wholeMsgLen - *offset) < parms->globalDataLen) { if (!asn_realloc(wholeMsg, wholeMsgLen)) { DEBUGMSGTL(("localsm", "building global data failed.\n")); return SNMPERR_TOO_LONG; } } *offset += parms->globalDataLen; memcpy(*wholeMsg + *wholeMsgLen - *offset, parms->globalData, parms->globalDataLen); /* * Total packet sequence. */ rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset); if (rc == 0) { DEBUGMSGTL(("localsm", "building master packet sequence failed.\n")); return SNMPERR_TOO_LONG; } DEBUGMSGTL(("localsm", "LOCALSM processing completed.\n")); return SNMPERR_SUCCESS; }
int tsm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) { u_char **wholeMsg = parms->wholeMsg; size_t *offset = parms->wholeMsgOffset; int rc; size_t *wholeMsgLen = parms->wholeMsgLen; netsnmp_tsmSecurityReference *tsmSecRef; netsnmp_tmStateReference *tmStateRef; int tmStateRefLocal = 0; DEBUGMSGTL(("tsm", "Starting TSM processing\n")); /* if we have this, then this message to be sent is in response to something that came in earlier and the tsmSecRef was created by the tsm_process_in_msg. */ tsmSecRef = parms->secStateRef; if (tsmSecRef) { /* 4.2, step 1: If there is a securityStateReference (Response or Report message), then this Security Model uses the cached information rather than the information provided by the ASI. */ /* 4.2, step 1: Extract the tmStateReference from the securityStateReference cache. */ netsnmp_assert_or_return(NULL != tsmSecRef->tmStateRef, SNMPERR_GENERR); tmStateRef = tsmSecRef->tmStateRef; /* 4.2 step 1: Set the tmRequestedSecurityLevel to the value of the extracted tmTransportSecurityLevel. */ tmStateRef->requestedSecurityLevel = tmStateRef->transportSecurityLevel; /* 4.2 step 1: Set the tmSameSecurity parameter in the tmStateReference cache to true. */ tmStateRef->sameSecurity = NETSNMP_TM_USE_SAME_SECURITY; /* 4.2 step 1: The cachedSecurityData for this message can now be discarded. */ SNMP_FREE(parms->secStateRef); } else { /* 4.2, step 2: If there is no securityStateReference (e.g., a Request-type or Notification message), then create a tmStateReference cache. */ tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference); netsnmp_assert_or_return(NULL != tmStateRef, SNMPERR_GENERR); tmStateRefLocal = 1; /* XXX: we don't actually use this really in our implementation */ /* 4.2, step 2: Set tmTransportDomain to the value of transportDomain, tmTransportAddress to the value of transportAddress */ /* 4.2, step 2: and tmRequestedSecurityLevel to the value of securityLevel. */ tmStateRef->requestedSecurityLevel = parms->secLevel; /* 4.2, step 2: Set the transaction-specific tmSameSecurity parameter to false. */ tmStateRef->sameSecurity = NETSNMP_TM_SAME_SECURITY_NOT_REQUIRED; if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TSM_USE_PREFIX)) { /* XXX: probably shouldn't be a hard-coded list of supported transports */ /* 4.2, step 2: If the snmpTsmConfigurationUsePrefix object is set to true, then use the transportDomain to look up the corresponding prefix. */ const char *prefix; if (strncmp("ssh:",parms->session->peername,4) == 0) prefix = "ssh:"; else if (strncmp("dtls:",parms->session->peername,5) == 0) prefix = "dtls:"; else if (strncmp("tls:",parms->session->peername,4) == 0) prefix = "tls:"; else { /* 4.2, step 2: If the prefix lookup fails for any reason, then the snmpTsmUnknownPrefixes counter is incremented, an error indication is returned to the calling module, and message processing stops. */ snmp_increment_statistic(STAT_TSM_SNMPTSMUNKNOWNPREFIXES); SNMP_FREE(tmStateRef); return SNMPERR_GENERR; } /* 4.2, step 2: If the lookup succeeds, but there is no prefix in the securityName, or the prefix returned does not match the prefix in the securityName, or the length of the prefix is less than 1 or greater than 4 US-ASCII alpha-numeric characters, then the snmpTsmInvalidPrefixes counter is incremented, an error indication is returned to the calling module, and message processing stops. */ if (strchr(parms->secName, ':') == 0 || strlen(prefix)+1 >= parms->secNameLen || strncmp(parms->secName, prefix, strlen(prefix)) != 0 || parms->secName[strlen(prefix)] != ':') { /* Note: since we're assiging the prefixes above the prefix lengths always meet the 1-4 criteria */ snmp_increment_statistic(STAT_TSM_SNMPTSMINVALIDPREFIXES); SNMP_FREE(tmStateRef); return SNMPERR_GENERR; } /* 4.2, step 2: Strip the transport-specific prefix and trailing ':' character (US-ASCII 0x3a) from the securityName. Set tmSecurityName to the value of securityName. */ memcpy(tmStateRef->securityName, parms->secName + strlen(prefix) + 1, parms->secNameLen - strlen(prefix) - 1); tmStateRef->securityNameLen = parms->secNameLen - strlen(prefix) -1; } else { /* 4.2, step 2: If the snmpTsmConfigurationUsePrefix object is set to false, then set tmSecurityName to the value of securityName. */ memcpy(tmStateRef->securityName, parms->secName, parms->secNameLen); tmStateRef->securityNameLen = parms->secNameLen; } } /* truncate the security name with a '\0' for safety */ tmStateRef->securityName[tmStateRef->securityNameLen] = '\0'; /* 4.2, step 3: Set securityParameters to a zero-length OCTET * STRING ('0400'). */ DEBUGDUMPHEADER("send", "tsm security parameters"); rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), 0); DEBUGINDENTLESS(); if (rc == 0) { DEBUGMSGTL(("tsm", "building msgSecurityParameters failed.\n")); if (tmStateRefLocal) SNMP_FREE(tmStateRef); return SNMPERR_TOO_LONG; } /* 4.2, step 4: Combine the message parts into a wholeMsg and calculate wholeMsgLength. */ while ((*wholeMsgLen - *offset) < parms->globalDataLen) { if (!asn_realloc(wholeMsg, wholeMsgLen)) { DEBUGMSGTL(("tsm", "building global data failed.\n")); if (tmStateRefLocal) SNMP_FREE(tmStateRef); return SNMPERR_TOO_LONG; } } *offset += parms->globalDataLen; memcpy(*wholeMsg + *wholeMsgLen - *offset, parms->globalData, parms->globalDataLen); /* 4.2, step 5: The wholeMsg, wholeMsgLength, securityParameters, and tmStateReference are returned to the calling Message Processing Model with the statusInformation set to success. */ /* For the Net-SNMP implemantion that actually means we start encoding the full packet sequence from here before returning it */ /* * Total packet sequence. */ rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset); if (rc == 0) { DEBUGMSGTL(("tsm", "building master packet sequence failed.\n")); if (tmStateRefLocal) SNMP_FREE(tmStateRef); return SNMPERR_TOO_LONG; } if (parms->pdu->transport_data && parms->pdu->transport_data != tmStateRef) { snmp_log(LOG_ERR, "tsm: needed to free transport data\n"); SNMP_FREE(parms->pdu->transport_data); } /* put the transport state reference into the PDU for the transport */ parms->pdu->transport_data = netsnmp_memdup(tmStateRef, sizeof(*tmStateRef)); if (!parms->pdu->transport_data) snmp_log(LOG_ERR, "tsm: malloc failure\n"); parms->pdu->transport_data_length = sizeof(*tmStateRef); if (tmStateRefLocal) SNMP_FREE(tmStateRef); DEBUGMSGTL(("tsm", "TSM processing completed.\n")); return SNMPERR_SUCCESS; }
int tsm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) { u_char **wholeMsg = parms->wholeMsg; size_t *offset = parms->wholeMsgOffset; int rc; size_t *wholeMsgLen = parms->wholeMsgLen; netsnmp_tsmSecurityReference *tsmSecRef; netsnmp_tmStateReference *tmStateRef; DEBUGMSGTL(("tsm", "Starting TSM processing\n")); /* if we have this, this message is in response to something that came in earlier */ tsmSecRef = parms->secStateRef; if (tsmSecRef) { /* section 4.2, step 1 */ if (tsmSecRef->tmStateRef) tmStateRef = tsmSecRef->tmStateRef; else tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference); if (NULL == tmStateRef) { snmp_log(LOG_ERR, "failed to allocate a tmStateReference\n"); return SNMPERR_GENERR; } tmStateRef->sameSecurity = NETSNMP_TM_USE_SAME_SECURITY; tmStateRef->requestedSecurityLevel = tsmSecRef->securityLevel; /* XXX: this may be freed automatically later by the library? */ SNMP_FREE(parms->secStateRef); } else { /* section 4.2, step 2 */ tmStateRef = SNMP_MALLOC_TYPEDEF(netsnmp_tmStateReference); if (tmStateRef == NULL) { return SNMPERR_GENERR; } tmStateRef->requestedSecurityLevel = parms->secLevel; tmStateRef->sameSecurity = NETSNMP_TM_SAME_SECURITY_NOT_REQUIRED; if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_LIB_TSM_USE_PREFIX)) { /* XXX: probably shouldn't be a hard-coded list of supported transports */ const char *prefix; if (strncmp("ssh:",parms->session->peername,4) == 0) prefix = "ssh:"; else if (strncmp("dtls:",parms->session->peername,4) == 0) prefix = "dtls:"; else return SNMPERR_GENERR; /* a: - lookup the prefix */ /* - if DNE, snmpTsmUnknownPrefixes++ and bail */ if (!prefix) { /* snmpTsmUnknownPrefixes++ */ return SNMPERR_GENERR; } /* - If secName doesn't have the prefix (or any): snmpTsmInvalidPrefixes++ and bail */ if (strchr(parms->secName, ':') == 0 || strlen(prefix)+1 >= parms->secNameLen || strncmp(parms->secName, prefix, strlen(prefix)) != 0 || parms->secName[strlen(prefix)] != ':') { /* snmpTsmInvalidPrefixes++ */ return SNMPERR_GENERR; } /* - Strip the prefix and trailing : */ /* set tmSecurityName to securityName minus stripped part */ memcpy(tmStateRef->securityName, parms->secName + strlen(prefix) + 1, parms->secNameLen - strlen(prefix) - 1); tmStateRef->securityNameLen = parms->secNameLen - strlen(prefix) -1; } else { /* set tmSecurityName to securityName */ memcpy(tmStateRef->securityName, parms->secName, parms->secNameLen); tmStateRef->securityNameLen = parms->secNameLen; } } tmStateRef->securityName[tmStateRef->securityNameLen] = '\0'; /* Section 4.2, Step 3: * - Set securityParameters to a zero-length OCTET STRING ('0400') * * We define here what the security message section will look like: * 04 00 -- null string */ DEBUGDUMPHEADER("send", "tsm security parameters"); rc = asn_realloc_rbuild_header(wholeMsg, wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), 0); DEBUGINDENTLESS(); if (rc == 0) { DEBUGMSGTL(("tsm", "building msgSecurityParameters failed.\n")); return SNMPERR_TOO_LONG; } /* Section 4.2, Step 4: * Combine the message parts into a wholeMsg and calculate wholeMsgLen */ /* * Copy in the msgGlobalData and msgVersion. */ while ((*wholeMsgLen - *offset) < parms->globalDataLen) { if (!asn_realloc(wholeMsg, wholeMsgLen)) { DEBUGMSGTL(("tsm", "building global data failed.\n")); return SNMPERR_TOO_LONG; } } *offset += parms->globalDataLen; memcpy(*wholeMsg + *wholeMsgLen - *offset, parms->globalData, parms->globalDataLen); /* * Total packet sequence. */ rc = asn_realloc_rbuild_sequence(wholeMsg, wholeMsgLen, offset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset); if (rc == 0) { DEBUGMSGTL(("tsm", "building master packet sequence failed.\n")); return SNMPERR_TOO_LONG; } /* Section 4.2 Step 5: return everything */ if (parms->pdu->transport_data && parms->pdu->transport_data != tmStateRef) { snmp_log(LOG_ERR, "tsm: needed to free transport data\n"); SNMP_FREE(parms->pdu->transport_data); } /* put the transport state reference into the PDU for the transport */ if (SNMPERR_SUCCESS != memdup(&parms->pdu->transport_data, tmStateRef, sizeof(*tmStateRef))) { snmp_log(LOG_ERR, "tsm: malloc failure\n"); } parms->pdu->transport_data_length = sizeof(*tmStateRef); DEBUGMSGTL(("tsm", "TSM processing completed.\n")); return SNMPERR_SUCCESS; }
int ksm_rgenerate_out_msg(struct snmp_secmod_outgoing_params *parms) { krb5_auth_context auth_context = NULL; krb5_error_code retcode; krb5_ccache cc = NULL; int retval = SNMPERR_SUCCESS; krb5_data outdata, ivector; krb5_keyblock *subkey = NULL; #ifdef MIT_NEW_CRYPTO krb5_data input; krb5_enc_data output; unsigned int numcksumtypes; krb5_cksumtype *cksumtype_array; #else /* MIT_NEW_CRYPTO */ krb5_encrypt_block eblock; #endif /* MIT_NEW_CRYPTO */ size_t blocksize, encrypted_length; unsigned char *encrypted_data = NULL; int zero = 0, i; u_char *cksum_pointer, *endp = *parms->wholeMsg; krb5_cksumtype cksumtype; krb5_checksum pdu_checksum; u_char **wholeMsg = parms->wholeMsg; size_t *offset = parms->wholeMsgOffset, seq_offset; struct ksm_secStateRef *ksm_state = (struct ksm_secStateRef *) parms->secStateRef; int rc; DEBUGMSGTL(("ksm", "Starting KSM processing\n")); outdata.length = 0; outdata.data = NULL; ivector.length = 0; ivector.data = NULL; pdu_checksum.contents = NULL; if (!ksm_state) { /* * If we don't have a ksm_state, then we're a request. Get a * credential cache and build a ap_req. */ retcode = krb5_cc_default(kcontext, &cc); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_cc_default failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } DEBUGMSGTL(("ksm", "KSM: Set credential cache successfully\n")); /* * This seems odd, since we don't need this until later (or earlier, * depending on how you look at it), but because the most likely * errors are Kerberos at this point, I'll get this now to save * time not encoding the rest of the packet. * * Also, we need the subkey to encrypt the PDU (if required). */ retcode = krb5_mk_req(kcontext, &auth_context, AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, (char *) service_name, parms->session->peername, NULL, cc, &outdata); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_mk_req failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } DEBUGMSGTL(("ksm", "KSM: ticket retrieved successfully for \"%s/%s\" " "(may not be actual ticket sname)\n", service_name, parms->session->peername)); } else { /* * Grab the auth_context from our security state reference */ auth_context = ksm_state->auth_context; /* * Bundle up an AP_REP. Note that we do this only when we * have a security state reference (which means we're in an agent * and we're sending a response). */ DEBUGMSGTL(("ksm", "KSM: Starting reply processing.\n")); retcode = krb5_mk_rep(kcontext, auth_context, &outdata); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_mk_rep failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } DEBUGMSGTL(("ksm", "KSM: Finished with krb5_mk_rep()\n")); } /* * If we have to encrypt the PDU, do that now */ if (parms->secLevel == SNMP_SEC_LEVEL_AUTHPRIV) { DEBUGMSGTL(("ksm", "KSM: Starting PDU encryption.\n")); /* * It's weird - * * If we're on the manager, it's a local subkey (because that's in * our AP_REQ) * * If we're on the agent, it's a remote subkey (because that comes * FROM the received AP_REQ). */ if (ksm_state) retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey); else retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey); if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_auth_con_getlocalsubkey failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } /* * Note that here we need to handle different things between the * old and new crypto APIs. First, we need to get the final encrypted * length of the PDU. */ #ifdef MIT_NEW_CRYPTO retcode = krb5_c_encrypt_length(kcontext, subkey->enctype, parms->scopedPduLen, &encrypted_length); if (retcode) { DEBUGMSGTL(("ksm", "Encryption length calculation failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } #else /* MIT_NEW_CRYPTO */ krb5_use_enctype(kcontext, &eblock, subkey->enctype); retcode = krb5_process_key(kcontext, &eblock, subkey); if (retcode) { DEBUGMSGTL(("ksm", "krb5_process_key failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } encrypted_length = krb5_encrypt_size(parms->scopedPduLen, eblock.crypto_entry); #endif /* MIT_NEW_CRYPTO */ encrypted_data = malloc(encrypted_length); if (!encrypted_data) { DEBUGMSGTL(("ksm", "KSM: Unable to malloc %d bytes for encrypt " "buffer: %s\n", parms->scopedPduLen, strerror(errno))); retval = SNMPERR_MALLOC; #ifndef MIT_NEW_CRYPTO krb5_finish_key(kcontext, &eblock); #endif /* ! MIT_NEW_CRYPTO */ goto error; } /* * We need to set up a blank initialization vector for the encryption. * Use a block of all zero's (which is dependent on the block size * of the encryption method). */ #ifdef MIT_NEW_CRYPTO retcode = krb5_c_block_size(kcontext, subkey->enctype, &blocksize); if (retcode) { DEBUGMSGTL(("ksm", "Unable to determine crypto block size: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } #else /* MIT_NEW_CRYPTO */ blocksize = krb5_enctype_array[subkey->enctype]->system->block_length; #endif /* MIT_NEW_CRYPTO */ ivector.data = malloc(blocksize); if (!ivector.data) { DEBUGMSGTL(("ksm", "Unable to allocate %d bytes for ivector\n", blocksize)); retval = SNMPERR_MALLOC; goto error; } ivector.length = blocksize; memset(ivector.data, 0, blocksize); /* * Finally! Do the encryption! */ #ifdef MIT_NEW_CRYPTO input.data = (char *) parms->scopedPdu; input.length = parms->scopedPduLen; output.ciphertext.data = (char *) encrypted_data; output.ciphertext.length = encrypted_length; retcode = krb5_c_encrypt(kcontext, subkey, KSM_KEY_USAGE_ENCRYPTION, &ivector, &input, &output); #else /* MIT_NEW_CRYPTO */ retcode = krb5_encrypt(kcontext, (krb5_pointer) parms->scopedPdu, (krb5_pointer) encrypted_data, parms->scopedPduLen, &eblock, ivector.data); krb5_finish_key(kcontext, &eblock); #endif /* MIT_NEW_CRYPTO */ if (retcode) { DEBUGMSGTL(("ksm", "KSM: krb5_encrypt failed: %s\n", error_message(retcode))); retval = SNMPERR_KRB5; snmp_set_detail(error_message(retcode)); goto error; } *offset = 0; rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), encrypted_data, encrypted_length); if (rc == 0) { DEBUGMSGTL(("ksm", "Building encrypted payload failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } DEBUGMSGTL(("ksm", "KSM: Encryption complete.\n")); } else { /* * Plaintext PDU (not encrypted) */ if (*parms->wholeMsgLen < parms->scopedPduLen) { DEBUGMSGTL(("ksm", "Not enough room for plaintext PDU.\n")); retval = SNMPERR_TOO_LONG; goto error; } } /* * Start encoding the msgSecurityParameters * * For now, use 0 for the response hint */ DEBUGMSGTL(("ksm", "KSM: scopedPdu added to payload\n")); seq_offset = *offset; rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), (long *) &zero, sizeof(zero)); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_string(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), (u_char *) outdata.data, outdata.length); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm AP_REQ failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } /* * Now, we need to pick the "right" checksum algorithm. For old * crypto, just pick CKSUMTYPE_RSA_MD5_DES; for new crypto, pick * one of the "approved" ones. */ #ifdef MIT_NEW_CRYPTO retcode = krb5_c_keyed_checksum_types(kcontext, subkey->enctype, &numcksumtypes, &cksumtype_array); if (retcode) { DEBUGMSGTL(("ksm", "Unable to find appropriate keyed checksum: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } if (numcksumtypes <= 0) { DEBUGMSGTL(("ksm", "We received a list of zero cksumtypes for this " "enctype (%d)\n", subkey->enctype)); snmp_set_detail("No valid checksum type for this encryption type"); retval = SNMPERR_KRB5; goto error; } /* * It's not clear to me from the API which checksum you're supposed * to support, so I'm taking a guess at the first one */ cksumtype = cksumtype_array[0]; krb5_free_cksumtypes(kcontext, cksumtype_array); DEBUGMSGTL(("ksm", "KSM: Choosing checksum type of %d (subkey type " "of %d)\n", cksumtype, subkey->enctype)); retcode = krb5_c_checksum_length(kcontext, cksumtype, &blocksize); if (retcode) { DEBUGMSGTL(("ksm", "Unable to determine checksum length: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } pdu_checksum.length = blocksize; #else /* MIT_NEW_CRYPTO */ if (ksm_state) cksumtype = ksm_state->cksumtype; else cksumtype = CKSUMTYPE_RSA_MD5_DES; if (!is_keyed_cksum(cksumtype)) { DEBUGMSGTL(("ksm", "Checksum type %d is not a keyed checksum\n", cksumtype)); snmp_set_detail("Checksum is not a keyed checksum"); retval = SNMPERR_KRB5; goto error; } if (!is_coll_proof_cksum(cksumtype)) { DEBUGMSGTL(("ksm", "Checksum type %d is not a collision-proof " "checksum\n", cksumtype)); snmp_set_detail("Checksum is not a collision-proof checksum"); retval = SNMPERR_KRB5; goto error; } pdu_checksum.length = krb5_checksum_size(kcontext, cksumtype); pdu_checksum.checksum_type = cksumtype; #endif /* MIT_NEW_CRYPTO */ /* * Note that here, we're just leaving blank space for the checksum; * we remember where that is, and we'll fill it in later. */ *offset += pdu_checksum.length; memset(*wholeMsg + *parms->wholeMsgLen - *offset, 0, pdu_checksum.length); cksum_pointer = *wholeMsg + *parms->wholeMsgLen - *offset; rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), pdu_checksum.length); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_int(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), (long *) &cksumtype, sizeof(cksumtype)); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset - seq_offset); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } rc = asn_realloc_rbuild_header(wholeMsg, parms->wholeMsgLen, parms->wholeMsgOffset, 1, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR), *offset - seq_offset); if (rc == 0) { DEBUGMSGTL(("ksm", "Building ksm security parameters failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } DEBUGMSGTL(("ksm", "KSM: Security parameter encoding completed\n")); /* * We're done with the KSM security parameters - now we do the global * header and wrap up the whole PDU. */ if (*parms->wholeMsgLen < parms->globalDataLen) { DEBUGMSGTL(("ksm", "Building global data failed.\n")); retval = SNMPERR_TOO_LONG; goto error; } *offset += parms->globalDataLen; memcpy(*wholeMsg + *parms->wholeMsgLen - *offset, parms->globalData, parms->globalDataLen); rc = asn_realloc_rbuild_sequence(wholeMsg, parms->wholeMsgLen, offset, 1, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), *offset); if (rc == 0) { DEBUGMSGTL(("ksm", "Building master packet sequence.\n")); retval = SNMPERR_TOO_LONG; goto error; } DEBUGMSGTL(("ksm", "KSM: PDU master packet encoding complete.\n")); /* * Now we need to checksum the entire PDU (since it's built). */ pdu_checksum.contents = malloc(pdu_checksum.length); if (!pdu_checksum.contents) { DEBUGMSGTL(("ksm", "Unable to malloc %d bytes for checksum\n", pdu_checksum.length)); retval = SNMPERR_MALLOC; goto error; } /* * If we didn't encrypt the packet, we haven't yet got the subkey. * Get that now. */ if (!subkey) { if (ksm_state) retcode = krb5_auth_con_getremotesubkey(kcontext, auth_context, &subkey); else retcode = krb5_auth_con_getlocalsubkey(kcontext, auth_context, &subkey); if (retcode) { DEBUGMSGTL(("ksm", "krb5_auth_con_getlocalsubkey failed: %s\n", error_message(retcode))); snmp_set_detail(error_message(retcode)); retval = SNMPERR_KRB5; goto error; } } #ifdef MIT_NEW_CRYPTO input.data = (char *) (*wholeMsg + *parms->wholeMsgLen - *offset); input.length = *offset; retcode = krb5_c_make_checksum(kcontext, cksumtype, subkey, KSM_KEY_USAGE_CHECKSUM, &input, &pdu_checksum); #else /* MIT_NEW_CRYPTO */ retcode = krb5_calculate_checksum(kcontext, cksumtype, *wholeMsg + *parms->wholeMsgLen - *offset, *offset, (krb5_pointer) subkey->contents, subkey->length, &pdu_checksum); #endif /* MIT_NEW_CRYPTO */ if (retcode) { DEBUGMSGTL(("ksm", "Calculate checksum failed: %s\n", error_message(retcode))); retval = SNMPERR_KRB5; snmp_set_detail(error_message(retcode)); goto error; } DEBUGMSGTL(("ksm", "KSM: Checksum calculation complete.\n")); memcpy(cksum_pointer, pdu_checksum.contents, pdu_checksum.length); DEBUGMSGTL(("ksm", "KSM: Writing checksum of %d bytes at offset %d\n", pdu_checksum.length, cksum_pointer - (*wholeMsg + 1))); DEBUGMSGTL(("ksm", "KSM: Checksum:")); for (i = 0; i < pdu_checksum.length; i++) DEBUGMSG(("ksm", " %02x", (unsigned int) pdu_checksum.contents[i])); DEBUGMSG(("ksm", "\n")); /* * If we're _not_ called as part of a response (null ksm_state), * then save the auth_context for later using our cache routines. */ if (!ksm_state) { if ((retval = ksm_insert_cache(parms->pdu->msgid, auth_context, (u_char *) parms->secName, parms->secNameLen)) != SNMPERR_SUCCESS) goto error; auth_context = NULL; } DEBUGMSGTL(("ksm", "KSM processing complete!\n")); error: if (pdu_checksum.contents) #ifdef MIT_NEW_CRYPTO krb5_free_checksum_contents(kcontext, &pdu_checksum); #else /* MIT_NEW_CRYPTO */ free(pdu_checksum.contents); #endif /* MIT_NEW_CRYPTO */ if (ivector.data) free(ivector.data); if (subkey) krb5_free_keyblock(kcontext, subkey); if (encrypted_data) free(encrypted_data); if (cc) krb5_cc_close(kcontext, cc); if (auth_context && !ksm_state) krb5_auth_con_free(kcontext, auth_context); return retval; }