Server Password Management Behavior

  • Any plain-text password is converted to a hashed value as soon as possible
  • The plain-text password is not exposed in any debug traces within a production build (PRODUCTION=1)
  • The plain-text password can only be exposed in initial input buffer debug traces within a debug build (DEBUG=1)
    • DEBUG_LOG_TLS=1 also required for NETCONF over TLS
    • NETCONF over TLS log tracing not available in binary only packages
  • The plain-text password is not saved in memory or disk by the server
  • The plain-text password is not available to SIL or SIL-SA code
  • Standard "crypt-hash" format "crypt" and "crypt_r" functions used by the server




IANA crypt-hash Data Type



  • The iana-crypt-hash YANG module contains a data type called crypt-hash.
  • This is the preferred method for setting passwords through YANG.
  • Either the clear-text or hashed value can be passed by the client.
    • The initial plain-text value is in crypt-hash format (e.g., $0$thisisatest)



  typedef crypt-hash {
    type string {
      pattern
        '$0$.*'
      + '|$1$[a-zA-Z0-9./]{1,8}$[a-zA-Z0-9./]{22}'
      + '|$5$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{43}'
      + '|$6$(rounds=\d+$)?[a-zA-Z0-9./]{1,16}$[a-zA-Z0-9./]{86}';
    }
    description
      "The crypt-hash type is used to store passwords using
       a hash function.  The algorithms for applying the hash
       function and encoding the result are implemented in
       various UNIX systems as the function crypt(3).

       A value of this type matches one of the forms:

         $0$<clear text password>
         $<id>$<salt>$<password hash>
         $<id>$<parameter>$<salt>$<password hash>

       The '$0$' prefix signals that the value is clear text.  When
       such a value is received by the server, a hash value is
       calculated, and the string '$<id>$<salt>$' or
       $<id>$<parameter>$<salt>$ is prepended to the result.  This
       value is stored in the configuration data store.
       If a value starting with '$<id>$', where <id> is not '0', is
       received, the server knows that the value already represents a
       hashed value and stores it 'as is' in the data store.

       When a server needs to verify a password given by a user, it
       finds the stored password hash string for that user, extracts
       the salt, and calculates the hash with the salt and given
       password as input.  If the calculated hash value is the same
       as the stored value, the password given by the client is
       accepted.

       This type defines the following hash functions:

         id | hash function | feature
         ---+---------------+-------------------
          1 | MD5           | crypt-hash-md5
          5 | SHA-256       | crypt-hash-sha-256
          6 | SHA-512       | crypt-hash-sha-512

       The server indicates support for the different hash functions
       by advertising the corresponding feature.";
    reference
      "IEEE Std 1003.1-2008 - crypt() function
       RFC 1321: The MD5 Message-Digest Algorithm
       FIPS.180-4.2012: Secure Hash Standard (SHS)";
  }


Example YANG Usage (ietf-system.yang)


         leaf password {
           type ianach:crypt-hash;
           description
             "The password for this entry.";
         }





YANG Extension openconfig-hashed-value


  • The module openconfig-extensions.yang has a YANG extension called "openconfig-hashed-value"
    • This data type is only supported in the 20.10 release train, starting in 20.10-6
  • This causes the leaf or leaf-list node that contains the extension to be treated as a special password
    • The initial value is a plain-text password string (e.g., thisisatest)
  • If this extension is found then the leaf or leaf-list will be treated in this manner. 
    • There is no way to disable this behavior
    • Do not use this extension if you do not want the OpenConfig defined behavior.



  extension openconfig-hashed-value {
    description
      "This extension provides an annotation on schema nodes to
      indicate that the corresponding value should be stored and
      reported in hashed form.

      Hash algorithms are by definition not reversible. Clients
      reading the configuration or applied configuration for the node
      should expect to receive only the hashed value. Values written
      in cleartext will be hashed. This annotation may be used on
      nodes such as secure passwords in which the device never reports
      a cleartext value, even if the input is provided as cleartext.";
  }




Example YANG Usage (openconfig-aaa.yang)


    leaf admin-password {
      type string;
      oc-ext:openconfig-hashed-value;
      description
        "The admin/root password, supplied as a cleartext string.
        The system should hash and only store the password as a
        hashed value.";
    }





Checking the Password with crypt or crypt_r


  • The GNU C Library is required to use the functions in crypt.h
    • If UCLINUX=1 then this library is not available in the server
  • The "crypt" function is used in a single-threaded server
  • The "crypt_r" function is used if PTHREADS=1 is used to build the server
  • Tutorial on using crypt_r: https://stackoverflow.com/questions/9335777/crypt-r-example


Basic Procedure


  1. Extract the salt from the start of the saved hashed password string
  2. Run crypt or crypt_r using the offered plain-text password and the extracted salt
  3. Compare the result to the entire saved password value



Example : test-ochash.yang


module test-ochash {
  yang-version 1.1;
  namespace "http://netconfcentral.org/ns/test-ochash";
  prefix toch;
  import openconfig-extensions { prefix oc-ext; }

  revision 2021-02-26;

  container octop {
   leaf ochash {
     type string;
     oc-ext:openconfig-hashed-value;
   }
 }

}



  • In this example the SIL code for the /octop/ochash leaf will save the hashed password somewhere in the system
    • The actual configuration value can also be retrieved from the server by the SIL code
  • The password saved is "thisisatest" (quotes not saved)
  • The following example function tests the offered password. 
    • It could be used in any program, not just SIL or SIL-SA code


Saved Password


andy@localhost> get-config source=running

rpc-reply {
  data {
    octop {
      ochash $6$bYPSvlTU3UYq4R2d$2gUvlnTKmgxBHi1NBZBSKwJiPs6zqO7PN35Zvfin3RidwUnFDUSeJ2GgyBAmTVorv..mXgg12naL6j9Xs2njo.
    }
  }
}

andy@localhost> 



Test Offered Password


/**
 * @brief Check a plain-text password against the saved hashed value
 * @param offered The plain-text password to check
 * @param hashed The saved crypt-hash password string
 * @return true if the offered password matches the hashed value
 */
static boolean
    test_password (const char *offered,
                   const char *hashed)
{
    int h_len = strlen(hashed);
    int copy_len = 0;

    /* get the salt length from the crypt-hash string */
    if (!strncmp(hashed, "$1$", 3)) {
        copy_len = 12;   // 3 + 8 + 1
    } else if (!strncmp(hashed, "$5$", 3) ||
               !strncmp(hashed, "$6$", 3)) {
        copy_len = 20;  // 3 + 16 + 1
    } else {
        return false;  // really an error!
    }

    if (h_len <= copy_len) {
        return false;  // really an error
    }

    /* extract the salt from the saved hash */
    char salt[22];
    *salt = 0;
    (void)strncpy(salt, hashed, copy_len);
    salt[copy_len] = 0;

    boolean result;

#ifdef HAS_CRYPT_R
    /* use the GNU re-entrant version of crypt so this will work
     * OK in all PTHREADS scenarios
     */
    struct crypt_data *crdata = m__getObj(struct crypt_data);
    if (crdata == NULL) {
        result = false;    // ERR_INTERNAL_MEM
    } else {
        crdata->initialized = 0;
        char *crypt_result = crypt_r(offered, salt, crdata);
        if (crypt_result) {
            result = (strcmp(crypt_result, hashed) == 0);
        }
        m__free(crdata);
    }
#else
    /* use the UNISTD non-re-entrant version of crypt
     * THIS WILL NOT WORK IN PTHREADS SERVER
     */
    char *crypt_result = crypt(offered, salt);
    result = (strcmp(crypt_result, hashed) == 0);
#endif  // HAS_CRYPT_R

    return result;
}



ncx:password is Deprecated! Do Not Use!


  • netconfd-pro has a YANG extension called "ncx:password" that existed before either of the previous two options.
  • This extension causes the password in the associated leaf to be stored in plain-text if used in a configuration data node.
  • The extension only causes the plain-text password to be displayed as 4 asterisks "****"
  • The actual XML or JSON message will include the plain-text password