VirtualBox

source: vbox/trunk/include/iprt/crypto/spc.h@ 76557

Last change on this file since 76557 was 76557, checked in by vboxsync, 6 years ago

include/iprt: Use IPRT_INCLUDED_ rather than _iprt_ as header guard prefix, letting scm enforce this (thereby avoiding copy&paste errors like rsa.h).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.3 KB
Line 
1/** @file
2 * IPRT - Crypto - Microsoft SPC / Authenticode.
3 */
4
5/*
6 * Copyright (C) 2006-2019 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef IPRT_INCLUDED_crypto_spc_h
27#define IPRT_INCLUDED_crypto_spc_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <iprt/asn1.h>
33#include <iprt/crypto/x509.h>
34#include <iprt/crypto/pkcs7.h>
35#include <iprt/md5.h>
36#include <iprt/sha.h>
37
38
39RT_C_DECLS_BEGIN
40
41/** @defgroup grp_rt_cr_spc RTCrSpc - Microsoft Authenticode
42 * @ingroup grp_rt_crypto
43 * @{
44 */
45
46/**
47 * PE Image page hash table, generic union.
48 *
49 * @remarks This table isn't used by ldrPE.cpp, it walks the table in a generic
50 * fashion using the hash size. So, we can ditch it if we feel like it.
51 */
52typedef union RTCRSPCPEIMAGEPAGEHASHES
53{
54 /** MD5 page hashes. */
55 struct
56 {
57 /** The file offset. */
58 uint32_t offFile;
59 /** The hash. */
60 uint8_t abHash[RTSHA1_HASH_SIZE];
61 } aMd5[1];
62
63 /** SHA-1 page hashes. */
64 struct
65 {
66 /** The file offset. */
67 uint32_t offFile;
68 /** The hash. */
69 uint8_t abHash[RTSHA1_HASH_SIZE];
70 } aSha1[1];
71
72 /** SHA-256 page hashes. */
73 struct
74 {
75 /** The file offset. */
76 uint32_t offFile;
77 /** The hash. */
78 uint8_t abHash[RTSHA256_HASH_SIZE];
79 } aSha256[1];
80
81 /** SHA-512 page hashes. */
82 struct
83 {
84 /** The file offset. */
85 uint32_t offFile;
86 /** The hash. */
87 uint8_t abHash[RTSHA512_HASH_SIZE];
88 } aSha512[1];
89
90 /** Generic view of ONE hash. */
91 struct
92 {
93 /** The file offset. */
94 uint32_t offFile;
95 /** Variable length hash field. */
96 uint8_t abHash[1];
97 } Generic;
98} RTCRSPCPEIMAGEPAGEHASHES;
99/** Pointer to a PE image page hash table union. */
100typedef RTCRSPCPEIMAGEPAGEHASHES *PRTCRSPCPEIMAGEPAGEHASHES;
101/** Pointer to a const PE image page hash table union. */
102typedef RTCRSPCPEIMAGEPAGEHASHES const *PCRTCRSPCPEIMAGEPAGEHASHES;
103
104
105/**
106 * Serialization wrapper for raw RTCRSPCPEIMAGEPAGEHASHES data.
107 */
108typedef struct RTCRSPCSERIALIZEDPAGEHASHES
109{
110 /** The page hashes are within a set. Dunno if there could be multiple
111 * entries in this set, never seen it yet, so I doubt it. */
112 RTASN1SETCORE SetCore;
113 /** Octet string containing the raw data. */
114 RTASN1OCTETSTRING RawData;
115
116 /** Pointer to the hash data within that string.
117 * The hash algorithm is given by the object attribute type in
118 * RTCRSPCSERIALIZEDOBJECTATTRIBUTE. It is generally the same as for the
119 * whole image hash. */
120 PCRTCRSPCPEIMAGEPAGEHASHES pData;
121 /** Field the user can use to store the number of pages in pData. */
122 uint32_t cPages;
123} RTCRSPCSERIALIZEDPAGEHASHES;
124/** Pointer to a serialized wrapper for page hashes. */
125typedef RTCRSPCSERIALIZEDPAGEHASHES *PRTCRSPCSERIALIZEDPAGEHASHES;
126/** Pointer to a const serialized wrapper for page hashes. */
127typedef RTCRSPCSERIALIZEDPAGEHASHES const *PCRTCRSPCSERIALIZEDPAGEHASHES;
128RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDPAGEHASHES, RTDECL, RTCrSpcSerializedPageHashes, SetCore.Asn1Core);
129
130RTDECL(int) RTCrSpcSerializedPageHashes_UpdateDerivedData(PRTCRSPCSERIALIZEDPAGEHASHES pThis);
131
132
133/**
134 * Data type selection for RTCRSPCSERIALIZEDOBJECTATTRIBUTE.
135 */
136typedef enum RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE
137{
138 /** Invalid zero entry. */
139 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_INVALID = 0,
140 /** Not present pro forma. */
141 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_NOT_PRESENT,
142 /** Unknown object. */
143 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN,
144 /** SHA-1 page hashes (pPageHashes). */
145 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1,
146 /** SHA-256 page hashes (pPageHashes). */
147 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2,
148 /** End of valid values. */
149 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_END,
150 /** Blow up the type to at least 32-bits. */
151 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_32BIT_HACK
152} RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE;
153
154/**
155 * One serialized object attribute (PE image data).
156 */
157typedef struct RTCRSPCSERIALIZEDOBJECTATTRIBUTE
158{
159 /** Sequence core. */
160 RTASN1SEQUENCECORE SeqCore;
161 /** The attribute type. */
162 RTASN1OBJID Type;
163 /** The allocation of the data type. */
164 RTASN1ALLOCATION Allocation;
165 /** Indicates the valid value in the union. */
166 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType;
167 /** Union with data format depending on the Type. */
168 union
169 {
170 /** The unknown value (RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN). */
171 PRTASN1CORE pCore;
172 /** Page hashes (RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 or
173 * RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2). */
174 PRTCRSPCSERIALIZEDPAGEHASHES pPageHashes;
175 } u;
176} RTCRSPCSERIALIZEDOBJECTATTRIBUTE;
177/** Pointer to a serialized object attribute. */
178typedef RTCRSPCSERIALIZEDOBJECTATTRIBUTE *PRTCRSPCSERIALIZEDOBJECTATTRIBUTE;
179/** Pointer to a const serialized object attribute. */
180typedef RTCRSPCSERIALIZEDOBJECTATTRIBUTE const *PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE;
181RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDOBJECTATTRIBUTE, RTDECL, RTCrSpcSerializedObjectAttribute, SeqCore.Asn1Core);
182
183/** @name RTCRSPCSERIALIZEDOBJECTATTRIBUTE::Type values
184 * @{ */
185/** Serialized object attribute type for page hashes version 1. */
186#define RTCRSPC_PE_IMAGE_HASHES_V1_OID "1.3.6.1.4.1.311.2.3.1"
187/** Serialized object attribute type for page hashes version 2. */
188#define RTCRSPC_PE_IMAGE_HASHES_V2_OID "1.3.6.1.4.1.311.2.3.2"
189/** @} */
190
191
192/*
193 * Set of serialized object attributes (PE image data).
194 */
195RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRSPCSERIALIZEDOBJECTATTRIBUTES, RTCRSPCSERIALIZEDOBJECTATTRIBUTE, RTDECL,
196 RTCrSpcSerializedObjectAttributes);
197
198/** The UUID found in RTCRSPCSERIALIZEDOBJECT::Uuid for
199 * RTCRSPCSERIALIZEDOBJECTATTRIBUTES. */
200#define RTCRSPCSERIALIZEDOBJECT_UUID_STR "d586b5a6-a1b4-6624-ae05-a217da8e60d6"
201
202
203/**
204 * Decoded encapsulated data type selection in RTCRSPCSERIALIZEDOBJECT.
205 */
206typedef enum RTCRSPCSERIALIZEDOBJECTTYPE
207{
208 /** Invalid zero value. */
209 RTCRSPCSERIALIZEDOBJECTTYPE_INVALID = 0,
210 /** Serialized object attributes (RTCRSPCSERIALIZEDOBJECT_UUID_STR / pAttribs). */
211 RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES,
212 /** End of valid values. */
213 RTCRSPCSERIALIZEDOBJECTTYPE_END,
214 /** MAke sure the type is at least 32-bit wide. */
215 RTCRSPCSERIALIZEDOBJECTTYPE_32BIT_HACK = 0x7fffffff
216} RTCRSPCSERIALIZEDOBJECTTYPE;
217
218/**
219 * A serialized object (PE image data).
220 */
221typedef struct RTCRSPCSERIALIZEDOBJECT
222{
223 /** Sequence core. */
224 RTASN1SEQUENCECORE SeqCore;
225 /** The UUID of the data object. */
226 RTASN1OCTETSTRING Uuid;
227 /** Serialized data object. */
228 RTASN1OCTETSTRING SerializedData;
229
230 /** Indicates the valid pointer in the union. */
231 RTCRSPCSERIALIZEDOBJECTTYPE enmType;
232 /** Union of pointers shadowing SerializedData.pEncapsulated. */
233 union
234 {
235 /** Generic core pointer. */
236 PRTASN1CORE pCore;
237 /** Pointer to decoded data if Uuid is RTCRSPCSERIALIZEDOBJECT_UUID_STR. */
238 PRTCRSPCSERIALIZEDOBJECTATTRIBUTES pData;
239 } u;
240} RTCRSPCSERIALIZEDOBJECT;
241/** Pointer to a serialized object (PE image data). */
242typedef RTCRSPCSERIALIZEDOBJECT *PRTCRSPCSERIALIZEDOBJECT;
243/** Pointer to a const serialized object (PE image data). */
244typedef RTCRSPCSERIALIZEDOBJECT const *PCRTCRSPCSERIALIZEDOBJECT;
245RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSERIALIZEDOBJECT, RTDECL, RTCrSpcSerializedObject, SeqCore.Asn1Core);
246
247
248/**
249 * RTCRSPCSTRING choices.
250 */
251typedef enum RTCRSPCSTRINGCHOICE
252{
253 /** Invalid zero value. */
254 RTCRSPCSTRINGCHOICE_INVALID = 0,
255 /** Not present. */
256 RTCRSPCSTRINGCHOICE_NOT_PRESENT,
257 /** UCS-2 string (pUcs2). */
258 RTCRSPCSTRINGCHOICE_UCS2,
259 /** ASCII string (pAscii). */
260 RTCRSPCSTRINGCHOICE_ASCII,
261 /** End of valid values. */
262 RTCRSPCSTRINGCHOICE_END,
263 /** Blow the type up to 32-bit. */
264 RTCRSPCSTRINGCHOICE_32BIT_HACK = 0x7fffffff
265} RTCRSPCSTRINGCHOICE;
266
267/**
268 * Stupid microsoft choosy string type.
269 */
270typedef struct RTCRSPCSTRING
271{
272 /** Dummy core. */
273 RTASN1DUMMY Dummy;
274 /** Allocation of what the pointer below points to. */
275 RTASN1ALLOCATION Allocation;
276 /** Pointer choice.*/
277 RTCRSPCSTRINGCHOICE enmChoice;
278 /** Pointer union. */
279 union
280 {
281 /** Tag 0, implicit: UCS-2 (BMP) string. */
282 PRTASN1STRING pUcs2;
283 /** Tag 1, implicit: ASCII (IA5) string. */
284 PRTASN1STRING pAscii;
285 } u;
286} RTCRSPCSTRING;
287/** Pointer to a stupid microsoft string choice. */
288typedef RTCRSPCSTRING *PRTCRSPCSTRING;
289/** Pointer to a const stupid microsoft string choice. */
290typedef RTCRSPCSTRING const *PCRTCRSPCSTRING;
291RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCSTRING, RTDECL, RTCrSpcString, Dummy.Asn1Core);
292
293
294/**
295 * RTCRSPCSTRING choices.
296 */
297typedef enum RTCRSPCLINKCHOICE
298{
299 /** Invalid zero value. */
300 RTCRSPCLINKCHOICE_INVALID = 0,
301 /** Not present. */
302 RTCRSPCLINKCHOICE_NOT_PRESENT,
303 /** URL (ASCII) string (pUrl). */
304 RTCRSPCLINKCHOICE_URL,
305 /** Serialized object (pMoniker). */
306 RTCRSPCLINKCHOICE_MONIKER,
307 /** Filename (pT2). */
308 RTCRSPCLINKCHOICE_FILE,
309 /** End of valid values. */
310 RTCRSPCLINKCHOICE_END,
311 /** Blow the type up to 32-bit. */
312 RTCRSPCLINKCHOICE_32BIT_HACK = 0x7fffffff
313} RTCRSPCLINKCHOICE;
314
315/**
316 * PE image data link.
317 */
318typedef struct RTCRSPCLINK
319{
320 /** Dummy core. */
321 RTASN1DUMMY Dummy;
322 /** Allocation of what the pointer below points to. */
323 RTASN1ALLOCATION Allocation;
324 /** Pointer choice.*/
325 RTCRSPCLINKCHOICE enmChoice;
326 /** Pointer union. */
327 union
328 {
329 /** Tag 0, implicit: An URL encoded as an IA5 STRING. */
330 PRTASN1STRING pUrl;
331 /** Tag 1, implicit: A serialized object. */
332 PRTCRSPCSERIALIZEDOBJECT pMoniker;
333 /** Tag 2, explicit: The default, a file name.
334 * Documented to be set to "<<<Obsolete>>>" when used. */
335 struct
336 {
337 /** Context tag 2. */
338 RTASN1CONTEXTTAG2 CtxTag2;
339 /** The file name string. */
340 RTCRSPCSTRING File;
341 } *pT2;
342 } u;
343} RTCRSPCLINK;
344/** Poitner to a PE image data link. */
345typedef RTCRSPCLINK *PRTCRSPCLINK;
346/** Poitner to a const PE image data link. */
347typedef RTCRSPCLINK const *PCRTCRSPCLINK;
348RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCLINK, RTDECL, RTCrSpcLink, Dummy.Asn1Core);
349
350
351#if 0 /** @todo Might not be the correct bit order. */
352/**
353 * Flag values for RTCRSPCPEIMAGEDATA::Flags and RTCRSPCPEIMAGEDATA::fFlags.
354 */
355typedef enum RTCRSPCPEIMAGEFLAGS
356{
357 RTCRSPCPEIMAGEFLAGS_INCLUDE_RESOURCES = 0,
358 RTCRSPCPEIMAGEFLAGS_INCLUDE_DEBUG_INFO = 1,
359 RTCRSPCPEIMAGEFLAGS_IMPORT_ADDRESS_TABLE = 2
360} RTCRSPCPEIMAGEFLAGS;
361#endif
362
363
364/**
365 * Authenticode PE Image data.
366 */
367typedef struct RTCRSPCPEIMAGEDATA
368{
369 /** Sequence core. */
370 RTASN1SEQUENCECORE SeqCore;
371 /** One of the RTCRSPCPEIMAGEFLAGS value, default is
372 * RTCRSPCPEIMAGEFLAGS_INCLUDE_RESOURCES. Obsolete with v2 page hashes? */
373 RTASN1BITSTRING Flags;
374 /** Tag 0, explicit: Link to the data. */
375 struct
376 {
377 /** Context tag 0. */
378 RTASN1CONTEXTTAG0 CtxTag0;
379 /** Link to the data. */
380 RTCRSPCLINK File;
381 } T0;
382} RTCRSPCPEIMAGEDATA;
383/** Pointer to a authenticode PE image data representation. */
384typedef RTCRSPCPEIMAGEDATA *PRTCRSPCPEIMAGEDATA;
385/** Pointer to a const authenticode PE image data representation. */
386typedef RTCRSPCPEIMAGEDATA const *PCRTCRSPCPEIMAGEDATA;
387RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCPEIMAGEDATA, RTDECL, RTCrSpcPeImageData, SeqCore.Asn1Core);
388
389/** The object ID for SpcPeImageData. */
390#define RTCRSPCPEIMAGEDATA_OID "1.3.6.1.4.1.311.2.1.15"
391
392
393/**
394 * Data type selection for RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE.
395 */
396typedef enum RTCRSPCAAOVTYPE
397{
398 /** Invalid zero entry. */
399 RTCRSPCAAOVTYPE_INVALID = 0,
400 /** Not present (pro forma). */
401 RTCRSPCAAOVTYPE_NOT_PRESENT,
402 /** Unknown object. */
403 RTCRSPCAAOVTYPE_UNKNOWN,
404 /** PE image data (pPeImage). */
405 RTCRSPCAAOVTYPE_PE_IMAGE_DATA,
406 /** End of valid values. */
407 RTCRSPCAAOVTYPE_END,
408 /** Blow up the type to at least 32-bits. */
409 RTCRSPCAAOVTYPE_32BIT_HACK
410} RTCRSPCAAOVTYPE;
411
412/**
413 * Authenticode attribute type and optional value.
414 *
415 * Note! Spec says the value should be explicitly tagged, but in real life
416 * it isn't. So, not very optional?
417 */
418typedef struct RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE
419{
420 /** Sequence core. */
421 RTASN1SEQUENCECORE SeqCore;
422 /** An object ID indicating the type of the value. */
423 RTASN1OBJID Type;
424 /** Allocation of the optional data value. */
425 RTASN1ALLOCATION Allocation;
426 /** The valid pointer. */
427 RTCRSPCAAOVTYPE enmType;
428 /** The value part depends on the Type. */
429 union
430 {
431 /** RTCRSPCAAOVTYPE_UNKNOWN / Generic. */
432 PRTASN1CORE pCore;
433 /** RTCRSPCAAOVTYPE_PE_IMAGE_DATA / RTCRSPCPEIMAGEDATA_OID. */
434 PRTCRSPCPEIMAGEDATA pPeImage;
435 } uValue;
436} RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE;
437/** Pointer to a authentication attribute type and optional value
438 * representation. */
439typedef RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE *PRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE;
440/** Pointer to a const authentication attribute type and optional value
441 * representation. */
442typedef RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE const *PCRTCRSPCATTRIBUTETYPEANDOPTIONALVALUE;
443RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE, RTDECL, RTCrSpcAttributeTypeAndOptionalValue, SeqCore.Asn1Core);
444
445
446/**
447 * Authenticode indirect data content.
448 */
449typedef struct RTCRSPCINDIRECTDATACONTENT
450{
451 /** Sequence core. */
452 RTASN1SEQUENCECORE SeqCore;
453 /** Additional data. */
454 RTCRSPCATTRIBUTETYPEANDOPTIONALVALUE Data;
455 /** The whole image digest. */
456 RTCRPKCS7DIGESTINFO DigestInfo;
457} RTCRSPCINDIRECTDATACONTENT;
458/** Pointer to a authenticode indirect data content representation. */
459typedef RTCRSPCINDIRECTDATACONTENT *PRTCRSPCINDIRECTDATACONTENT;
460/** Pointer to a const authenticode indirect data content representation. */
461typedef RTCRSPCINDIRECTDATACONTENT const *PCRTCRSPCINDIRECTDATACONTENT;
462RTASN1TYPE_STANDARD_PROTOTYPES(RTCRSPCINDIRECTDATACONTENT, RTDECL, RTCrSpcIndirectDataContent, SeqCore.Asn1Core);
463
464/** The object ID for SpcIndirectDataContent. */
465#define RTCRSPCINDIRECTDATACONTENT_OID "1.3.6.1.4.1.311.2.1.4"
466
467/**
468 * Check the sanity of an Authenticode SPCIndirectDataContent object.
469 *
470 * @returns IPRT status code
471 * @param pIndData The Authenticode SPCIndirectDataContent to
472 * check.
473 * @param pSignedData The related signed data object.
474 * @param fFlags RTCRSPCINDIRECTDATACONTENT_SANITY_F_XXX.
475 * @param pErrInfo Optional error info.
476 */
477RTDECL(int) RTCrSpcIndirectDataContent_CheckSanityEx(PCRTCRSPCINDIRECTDATACONTENT pIndData, PCRTCRPKCS7SIGNEDDATA pSignedData,
478 uint32_t fFlags, PRTERRINFO pErrInfo);
479/** @name RTCRSPCINDIRECTDATACONTENT_SANITY_F_XXX for RTCrSpcIndirectDataContent_CheckSanityEx.
480 * @{ */
481/** The digest hash algorithm must be known to IPRT. */
482#define RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH RT_BIT_32(0)
483/** PE image signing, check expectations of the spec. */
484#define RTCRSPCINDIRECTDATACONTENT_SANITY_F_PE_IMAGE RT_BIT_32(1)
485/** @} */
486
487/**
488 * Gets the first SPC serialized object attribute in a SPC PE image.
489 *
490 * @returns Pointer to the attribute with the given type, NULL if not found.
491 * @param pThis The Authenticode SpcIndirectDataContent.
492 * @param enmType The type of attribute to get.
493 */
494RTDECL(PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE)
495RTCrSpcIndirectDataContent_GetPeImageObjAttrib(PCRTCRSPCINDIRECTDATACONTENT pThis,
496 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE enmType);
497
498/** @} */
499
500RT_C_DECLS_END
501
502#endif
503
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette