/upload compared the per-node API key with a plain !=, which short-circuits on the first differing byte and so leaks a little information about how much of a guess was correct. The reason to fix it is less the timing channel itself -- an HTTP round trip is noisy -- than the inconsistency: enrollment.py and dynsec.py both went out of their way to use secrets.compare_digest for the same class of credential, so the codebase contradicted itself on whether this mattered. Now it does not. Also coalesces a missing api_key field to "" so compare_digest is never handed None, which would raise TypeError and turn a malformed node_keys document into a 500 instead of a 401. Closes logan/server-26#12