Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

进行HTTP摘要认证出错,没有qop参数的时候会报错 #269

Open
DarkiT opened this issue Aug 17, 2023 · 10 comments
Open

进行HTTP摘要认证出错,没有qop参数的时候会报错 #269

DarkiT opened this issue Aug 17, 2023 · 10 comments

Comments

@DarkiT
Copy link

DarkiT commented Aug 17, 2023

例如使用HTTP摘要认证登陆华为设备会提示:digest: qop must be specified
华为设备返回的摘要信息如下:
WWW-Authenticate: Digest realm="Huawei",nonce="66f38e5ec6ebedc7c65c16f1c0ea3f46", algorithm=SHA-256

@imroc
Copy link
Owner

imroc commented Aug 18, 2023

看起来设备没遵循RFC规范,qop是WWW-Authenticate响应中必带的参数:

qop

This parameter MUST be used by all implementations. It is a quoted string of one or more tokens indicating the "quality of protection" values supported by the server. The value "auth" indicates authentication; the value "auth-int" indicates authentication with integrity protection. See the descriptions below for calculating the response parameter value for the application of this choice. Unrecognized options MUST be ignored.

参考:https://httpwg.org/specs/rfc7616.html#authorization.request.header.field

@imroc
Copy link
Owner

imroc commented Aug 18, 2023

我在想,为了提升使用的便利性,req也不必遵循规范,当响应中没有 qop 参数时,默认指定为 auth

@imroc
Copy link
Owner

imroc commented Aug 18, 2023

已经release了个小版本,你可以升级试下

@DarkiT
Copy link
Author

DarkiT commented Aug 18, 2023

试了下,不行,我提交了一个Pull请求来处理了这个问题,您看看
更新

@imroc
Copy link
Owner

imroc commented Aug 21, 2023

@DarkiT 最新版做了微调,没用正则,试试看

@DarkiT
Copy link
Author

DarkiT commented Aug 21, 2023

@imroc 获取摘要参数没问题,validateQop() 和 resp() 方法需要修改下,不然计算出来的摘要信息过不了验证。


func (c *credentials) validateQop() error {
	if c.messageQop == "" {
		return nil
	}
	possibleQops := strings.Split(c.messageQop, ", ")
	var authSupport bool
	for _, qop := range possibleQops {
		if qop == "auth" {
			authSupport = true
			break
		}
	}
	if !authSupport {
		return errDigestQopNotSupported
	}

	return nil
}

func (c *credentials) resp() (string, error) {
	c.nc++

	b := make([]byte, 16)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		return "", err
	}
	c.cNonce = fmt.Sprintf("%x", b)[:32]

	ha1 := c.ha1()
	ha2 := c.ha2()

	if len(c.messageQop) == 0 {
		return c.h(fmt.Sprintf("%s:%s:%s", ha1, c.nonce, ha2)), nil
	}
	return c.kd(ha1, fmt.Sprintf("%s:%08x:%s:%s:%s",
		c.nonce, c.nc, c.cNonce, c.messageQop, ha2)), nil
}

@imroc
Copy link
Owner

imroc commented Aug 22, 2023

@DarkiT 默认qop已经赋值auth了,相当于默认按auth方式计算摘要,怎么会过不了验证呢

@DarkiT
Copy link
Author

DarkiT commented Aug 22, 2023

主要是这种不标准的摘要在摄像头及流媒体认证里面使用的很广 ,跟常见的网站摘要认证有区别,比如海康、华为的摄像头北向接口基本上都是这种摘要认证,是没有qop参数的,都是这样的:
WWW-Authenticate: Digest realm="Huawei",nonce="66f38e5ec6ebedc7c65c16f1c0ea3f46", algorithm=SHA-256
他们计算摘要的方式略有有点区别,只传入了 HA1、NONCE、HA2进行计算。
c.h(fmt.Sprintf("%s:%s:%s", ha1, c.nonce, ha2))

所以我们要在validateQop()方法这里判断messageQop为空也是允许的,不能给他指定auth,然后在resp()方法里面根据messageQop来判断使用哪种方式计算摘要信息。

@imroc
Copy link
Owner

imroc commented Aug 23, 2023

明白了

@imroc
Copy link
Owner

imroc commented Aug 23, 2023

@DarkiT 又 release了小版本,试试

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants